能否用含窗口函数的纯SQL实现日期区间配对转换(无自连接)
问题
现有表T1包含id和event_date列(主键为(id, event_date)),存储的是某流程的起止日期且按顺序排列。需要生成表T2,将T1中第1条记录的日期作为start_date、第2条作为end_date,第3与第4条、第5与第6条等依次配对,直至处理完所有记录。询问是否可通过包含窗口函数的纯SQL语句(无需自连接、存储过程或函数)实现该需求,可考虑使用递归查询(WITH RECURSIVE)。
表结构及测试数据
T1表结构
create table T1 ( id bigint not null, event_date date not null, PRIMARY KEY (id, event_date) )
T1测试数据
insert into T1 VALUES ('354312','2020-03-01'), ('354312','2020-08-01'), ('354312','2020-12-01'), ('354312','2020-06-30'), ('354312','2020-09-30'), ('354312','2020-08-31'), ('354312','2020-10-31'), ('354312','2020-12-31')
目标表T2结构
create table T2 ( id bigint not null primary key, start_date date not null, end_date date )
解决方案
完全可以通过纯SQL结合窗口函数实现,无需自连接、存储过程或函数,也不需要递归查询,用ROW_NUMBER()窗口函数分组配对即可,具体实现如下:
实现SQL
WITH numbered_dates AS ( SELECT id, event_date, ROW_NUMBER() OVER (PARTITION BY id ORDER BY event_date) AS rn FROM T1 ) INSERT INTO T2 (id, start_date, end_date) SELECT id, MAX(CASE WHEN rn % 2 = 1 THEN event_date END) AS start_date, MAX(CASE WHEN rn % 2 = 0 THEN event_date END) AS end_date FROM numbered_dates GROUP BY id, (rn - 1) / 2 ORDER BY (rn - 1) / 2;
逻辑说明
- 生成行号:通过
ROW_NUMBER()给每个id下的记录按event_date排序生成连续行号,确保配对顺序符合日期排列; - 分组配对:利用
(rn - 1) / 2将行号1-2、3-4等依次归为同一组,实现两两配对; - 提取起止日期:用
CASE语句配合MAX()聚合函数,分别提取每组中的奇数行(起始日期)和偶数行(结束日期); - 兼容奇数记录数:若某个
id的记录数为奇数,最后一组的end_date会返回NULL,符合“处理完所有记录”的要求。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

