PostgreSQL - GROUP 后续行

Posted

技术标签:

【中文标题】PostgreSQL - GROUP 后续行【英文标题】:PostgreSQL - GROUP subsequent rows 【发布时间】:2013-12-07 20:29:56 【问题描述】:

我有一个表,其中包含一些按日期排序的记录。

我想获取每个后续​​组的开始和结束日期(按某些标准分组,例如位置)。

Example:

create table tbl (id int, date timestamp without time zone, 
                  position int);

insert into tbl values 
( 1 , '2013-12-01', 1),
( 2 , '2013-12-02', 2),
( 3 , '2013-12-03', 2),
( 4 , '2013-12-04', 2),
( 5 , '2013-12-05', 3),
( 6 , '2013-12-06', 3),
( 7 , '2013-12-07', 2),
( 8 , '2013-12-08', 2)

当然,如果我只是按位置分组,我会得到错误的结果,因为不同组的位置可能相同:

SELECT POSITION, min(date) MIN, max(date) MAX
FROM tbl GROUP BY POSITION

我会得到:

POSITION    MIN                             MAX
1           December, 01 2013 00:00:00+0000 December, 01 2013 00:00:00+0000
3           December, 05 2013 00:00:00+0000 December, 06 2013 00:00:00+0000
2           December, 02 2013 00:00:00+0000 December, 08 2013 00:00:00+0000

但我想要:

POSITION    MIN                             MAX
1           December, 01 2013 00:00:00+0000 December, 01 2013 00:00:00+0000
2           December, 02 2013 00:00:00+0000 December, 04 2013 00:00:00+0000
3           December, 05 2013 00:00:00+0000 December, 06 2013 00:00:00+0000
2           December, 07 2013 00:00:00+0000 December, 08 2013 00:00:00+0000

我找到了一个使用变量的solution for mysql,我可以移植它,但我相信 PostgreSQL 可以使用它的高级特性(如窗口函数)以更智能的方式完成它。

我使用的是 PostgreSQL 9.2

【问题讨论】:

【参考方案1】:

可能有更优雅的解决方案,但试试这个:

WITH tmp_tbl AS (
SELECT *,
CASE WHEN lag(position,1) OVER(ORDER BY id)=position 
    THEN position 
    ELSE ROW_NUMBER() OVER(ORDER BY id)
    END AS grouping_col  
FROM tbl
)
, tmp_tbl2 AS(
SELECT position,date,
CASE WHEN lag(position,1)OVER(ORDER BY id)=position 
    THEN lag(grouping_col,1) OVER(ORDER BY id)
    ELSE ROW_NUMBER() OVER(ORDER BY id) 
    END AS grouping_col
FROM tmp_tbl
)
SELECT POSITION, min(date) MIN, max(date) MAX
FROM tmp_tbl2 GROUP BY grouping_col,position

【讨论】:

【参考方案2】:

*** 上有一些完整的答案,这里不再赘述,其原理是按照以下的区别对记录进行分组:

按日期排序时的行号(通过窗口函数) 日期与静态参考日期之间的差异。

所以你有一个系列,例如:

rownum datediff diff
1      1        0 ^
2      2        0 | first group
3      3        0 v
4      5        1 ^
5      6        1 | second group
6      7        1 v
7      9        2 ^
8      10       2 v third group

【讨论】:

以上是关于PostgreSQL - GROUP 后续行的主要内容,如果未能解决你的问题,请参考以下文章

优化 PostgreSql 查询以获取找到的记录总数和基于多个 group by 的分页所需的有限行数

PostgreSQL中group by中的窗口函数

2017.4.8 PostgreSQL象行中国 [杭州站]

必须出现在 postgresql 的 GROUP BY 子句中

优化 PostgreSQL 中的 JOIN -> GROUP BY 查询:所有索引都已经存在

PostgreSQL 分组错误