PostgreSQL 窗口函数:row_number() over (partition col order by col2)。

18

下面的结果集是从一条带有几个连接和一个联合的SQL查询中派生出来的。该SQL查询已经按日期和游戏对行进行了分组。我需要一个列来描述按日期列分区的游戏尝试次数。

Username   Game     ID   Date

johndoe1   Game_1   100  7/22/14 1:52 AM
johndoe1   Game_1   100  7/22/14 1:52 AM
johndoe1   Game_1   100  7/22/14 1:52 AM
johndoe1   Game_1   100  7/22/14 1:52 AM
johndoe1   Game_1   121  7/22/14 1:56 AM
johndoe1   Game_1   121  7/22/14 1:56 AM
johndoe1   Game_1   121  7/22/14 1:56 AM
johndoe1   Game_1   121  7/22/14 1:56 AM
johndoe1   Game_1   121  7/22/14 1:56 AM
johndoe1   Game_1   130  7/22/14 1:59 AM
johndoe1   Game_1   130  7/22/14 1:59 AM
johndoe1   Game_1   130  7/22/14 1:59 AM
johndoe1   Game_1   130  7/22/14 1:59 AM
johndoe1   Game_1   130  7/22/14 1:59 AM
johndoe1   Game_1   200  7/22/14 2:54 AM
johndoe1   Game_1   200  7/22/14 2:54 AM
johndoe1   Game_1   200  7/22/14 2:54 AM
johndoe1   Game_1   200  7/22/14 2:54 AM
johndoe1   Game_1   210  7/22/14 3:54 AM
johndoe1   Game_1   210  7/22/14 3:54 AM
johndoe1   Game_1   210  7/22/14 3:54 AM
johndoe1   Game_1   210  7/22/14 3:54 AM

我有以下 SQL 查询,枚举了分区内的行,但不完全正确,因为我想根据日期和游戏计算该游戏实例的次数。在这种情况下,johndoe1 根据时间戳尝试了五次 Game_1。

此查询返回以下结果集:

select *
, row_number() over (partition by ct."date" order by ct."date") as "Attempts"
from csv_temp as ct

Username   Game     ID   Date             Attempts  (Desired Attempts col.)

johndoe1   Game_1   100  7/22/14 1:52 AM  1          1
johndoe1   Game_1   100  7/22/14 1:52 AM  2          1
johndoe1   Game_1   100  7/22/14 1:52 AM  3          1
johndoe1   Game_1   100  7/22/14 1:52 AM  4          1
johndoe1   Game_1   121  7/22/14 1:56 AM  1          2
johndoe1   Game_1   121  7/22/14 1:56 AM  2          2
johndoe1   Game_1   121  7/22/14 1:56 AM  3          2
johndoe1   Game_1   121  7/22/14 1:56 AM  4          2
johndoe1   Game_1   121  7/22/14 1:56 AM  5          2
johndoe1   Game_1   130  7/22/14 1:59 AM  1          3   
johndoe1   Game_1   130  7/22/14 1:59 AM  2          3
johndoe1   Game_1   130  7/22/14 1:59 AM  3          3
johndoe1   Game_1   130  7/22/14 1:59 AM  4          3
johndoe1   Game_1   130  7/22/14 1:59 AM  5          3
johndoe1   Game_1   200  7/22/14 2:54 AM  1          4
johndoe1   Game_1   200  7/22/14 2:54 AM  2          4
johndoe1   Game_1   200  7/22/14 2:54 AM  3          4
johndoe1   Game_1   200  7/22/14 2:54 AM  4          4
johndoe1   Game_1   210  7/22/14 3:54 AM  1          5
johndoe1   Game_1   210  7/22/14 3:54 AM  2          5
johndoe1   Game_1   210  7/22/14 3:54 AM  3          5
johndoe1   Game_1   210  7/22/14 3:54 AM  4          5
任何指针都将是极大的帮助。

3
也许这篇文章能帮到您:http://java.dzone.com/articles/difference-between-rownumber 。 - Konstantin V. Salikhov
看着所需的结果,在“(所需尝试次数列)”组中行之间唯一的区别是“尝试次数”列。也许您可以按“用户名、游戏、ID”进行分组,添加“count(1)”以获取尝试次数,并添加“row_number()”以获取“(所需尝试次数列)”? - jakubiszon
1个回答

38

考虑使用partition by与你想要使用的group by字段类似,当分区值改变时,窗口函数重新从1开始计数。

编辑: 正如a_horse_with_no_name所指出的,对于这个需求,我们需要使用dense_rank()。与row_number()rank()不同,dense_rank()会重复分配它赋予的数字。row_number()必须对分区中的每一行都分配一个不同的值。rank()dense_rank()之间的区别是后者不“跳过”数字。

对于您的查询,请尝试:

dense_rank() over (partition by Username, Game order by ct."date") as "Attempts"

顺便说一下,不要按相同的字段进行分区和排序;如果只需要排序,那么只按顺序排列即可。但在这里并非如此。


3
就像示例中一样,每行只有一个用户名/游戏组合,每行都会获得不同的行号(row_number()从不生成重复数字)。应该是dense_rank() over (partition by Username, Game order by ct."date") - user330315
1
@a_horse_with_no_name 哦,非常正确 - 我专注于分区; 谢谢。 - Paul Maxwell
我没有足够的创造力想象“partition by”子句可以接受多个列,而且我分区错误了。谢谢你们两个! - user1951677
这个功能是什么时候在Postgres中出现的?它算是比较新的吗? - Justin Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接