sql - 不跳行的Postgresql GROUP BY?

标签 sql postgresql group-by

假设我在表中有这些数据:

 id | thing | operation | timestamp
----+-------+-----------+-----------
  0 | foo   |       add |         0
  0 | bar   |       add |         1
  1 | baz   |    remove |         2
  1 | dim   |       add |         3
  0 | foo   |    remove |         4
  0 | dim   |       add |         5

有什么方法可以构建一个 Postgres SQL 查询,该查询将按 id 和操作进行分组,但不会将具有较高时间戳值的行与具有较低时间戳值的行进行分组?我想从查询中得到这个:

 id |  things  | operation
----+----------+-----------
  0 | foo, bar |       add
  1 |      baz |    remove
  1 |      dim |       add
  0 |      foo |    remove
  0 |      dim |       add

基本上分组依据,但仅限于按时间戳排序的相邻行。

最佳答案

这是一个 gaps and islands问题(虽然这篇文章是针对 SQL-Server 的,但它很好地描述了问题,所以仍然适用于 Postgresql),并且可以使用排名函数解决:

SELECT  id,
        thing,
        operation,
        timestamp,
        ROW_NUMBER() OVER(ORDER BY timestamp) - 
                ROW_NUMBER() OVER(PARTITION BY id, operation ORDER BY Timestamp) AS groupingSet,
        ROW_NUMBER() OVER(ORDER BY timestamp) AS PositionInSet,
        ROW_NUMBER() OVER(PARTITION BY id, operation ORDER BY Timestamp) AS PositionInGroup
FROM    T
ORDER BY timestamp;

正如您所见,通过获取集合中的整体位置,并减去组中的位置,您可以识别岛屿,其中 (id, operation, groupingset) 的每个唯一组合代表一个岛屿:

id  thing   operation   timestamp   groupingSet PositionInSet   PositionInGroup
0   foo     add         0           0           1               1
0   bar     add         1           0           2               2           
1   baz     remove      2           2           3               1
1   dim     add         3           3           4               1
0   foo     remove      4           4           5               1
0   dim     add         5           3           6               3

然后你只需要把它放在一个子查询中,并按相关字段分组,然后使用 string_agg 连接你的东西:

SELECT  id, STRING_AGG(thing) AS things, operation
FROM    (   SELECT  id,
                    thing,
                    operation,
                    timestamp,
                    ROW_NUMBER() OVER(ORDER BY timestamp) - 
                            ROW_NUMBER() OVER(PARTITION BY id, operation ORDER BY Timestamp) AS groupingSet
            FROM    T
        ) AS t
GROUP BY id, operation, groupingset;

关于sql - 不跳行的Postgresql GROUP BY?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28560389/

相关文章:

mysql - 查询相当于临时表mysql

r - 使用dplyr的group_by进行split-apply-combine

database - Postgres 动态创建序列

c# - 在 GROUP BY MySQL 查询上读取 IDataReader

r - 使用 group_by 和列条件在数据框中查找值

mysql - 当查询没有任何行时显示默认记录

c# - 从 EF 查询获取 Id,然后使用它来删除记录

php - SQL 检查行是否包含一组值

postgresql - 将表从本地主机复制到远程服务器?

postgresql - 将客户端 UUID 转换为 SQL UUID