Mos*_*hev 3 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
Run Code Online (Sandbox Code Playgroud)
是否有任何方法可以构建一个Postgres SQL查询,该查询将按ID和操作进行分组,但是没有将具有更高时间戳值的行分组给那些具有更低时间戳的行?我想从查询中得到这个:
id | things | operation
----+----------+-----------
0 | foo, bar | add
1 | baz | remove
1 | dim | add
0 | foo | remove
0 | dim | add
Run Code Online (Sandbox Code Playgroud)
基本上分组,但仅限于按时间戳排序的相邻行.
这是一个空白和孤岛问题(尽管本文针对的是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;
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样,通过获取集合中的整体位置,并扣除组中的位置,您可以识别岛屿,其中每个独特的组合(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
Run Code Online (Sandbox Code Playgroud)
然后你只需要将它放在子查询中,并按相关字段分组,并使用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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
359 次 |
| 最近记录: |