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

Posted

技术标签:

【中文标题】PostgreSQL 窗口函数:row_number() over (partition col order by col2)【英文标题】:PostgreSQL window function: row_number() over (partition col order by col2) 【发布时间】:2014-10-23 03:02:52 【问题描述】:

以下结果集来自一个带有几个连接和一个联合的 sql 查询。 sql 查询已经对 Date 和 game 上的行进行了分组。我需要一个列来描述按日期列划分的游戏的尝试次数。

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

任何指针都会有很大帮助。

【问题讨论】:

也许这会有所帮助java.dzone.com/articles/difference-between-rownumber 查看所需结果,(Desired Attempts col.) 组中的行之间的唯一区别是Attempts 列。也许您可以按Username, Game, ID 分组,添加count(1) 以获取尝试次数并添加row_number() 以获取(Desired Attempts col.) 【参考方案1】:

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"

顺便说一句,您不会按相同的字段进行分区和排序;如果需要,只需订购就足够了。它不在这里。

【讨论】:

如示例中只有一个用户名/游戏组合,每行将在您的语句中获得不同的 row_number(row_number() 永远不会生成重复的数字)。应该是dense_rank() over (partition by Username, Game order by ct."date") @a_horse_with_no_name 哦,天哪,完全正确 - 我专注于分区;谢谢。 我没有足够的创意来想象“partition by”子句可以接受多个列,而且我分区不正确。谢谢你们! 这个功能什么时候出现在 postgres 中的?是不是比较新?

以上是关于PostgreSQL 窗口函数:row_number() over (partition col order by col2)的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL - 使用窗口函数时如何知道我在哪个分区?

为啥 row_number() 比使用偏移快?

Postgresql 根据单列或几列分组去重row_number() over() partition by

为啥将 ROW_NUMBER 定义为窗口函数?

使用 ROW_NUMBER() 窗口函数选择行

前 MariaDB 版本中的 Row_Number() 窗口函数