Oracle SQL根据起止日期生成多成员连续日期序列表
Oracle 实现日期区间展开为连续日期行
这个区间拆分为连续日期行的需求,用Oracle原生语法即可实现,不需要额外建日历辅助表,下面给两种可直接运行的方案,附逻辑说明。
方案1:全版本通用(兼容所有Oracle版本)
用Oracle原生CONNECT BY层级查询实现,写法简洁性能好:
SELECT t.Members, t.Start + LEVEL - 1 AS DATETIME FROM START_END_DATE_TABLE t CONNECT BY LEVEL <= t.End - t.Start + 1 AND PRIOR t.Members = t.Members AND PRIOR SYS_GUID() IS NOT NULL ORDER BY t.Members, DATETIME;
关键逻辑说明
- 日期计算规则:Oracle中DATE类型直接加减整数等价于加减对应天数,
End - Start +1计算的是当前区间包含首尾日期的总天数,刚好对应需要生成的行数 LEVEL是层级查询的内置计数器,从1开始逐行递增:第一行LEVEL=1时,Start +1 -1 = Start就是起始日期;最后一行LEVEL=总天数时,计算结果刚好等于截止日期,自动覆盖首尾日期PRIOR t.Members = t.Members作用是为每个成员单独生成连续序列,避免不同成员的日期数据交叉串联PRIOR SYS_GUID() IS NOT NULL是通用兼容写法,避免同个成员存在多条区间记录时触发循环连接报错,无论表结构是否存在重复值,加上都不会影响正常结果
方案2:12c及以上版本可选(递归CTE写法)
如果客户使用的是Oracle 12c及之后的版本,也可以用递归公用表表达式实现,逻辑更直白,适合新手理解:
WITH date_temp(Members, cur_date, end_date) AS ( -- 递归起点:取每个用户的起始日期作为第一行 SELECT Members, Start, End FROM START_END_DATE_TABLE UNION ALL -- 递归规则:每次日期加1,直到等于截止日期停止 SELECT Members, cur_date + 1, end_date FROM date_temp WHERE cur_date < end_date ) SELECT Members, cur_date AS DATETIME FROM date_temp ORDER BY Members, cur_date;
运行说明
- 两个方案输出结果完全一致,都会按成员逐行生成从起始到截止的所有日期,和你给出的预期输出完全匹配
- 因为你的Start、End字段已经是DATE类型,不需要额外做类型转换,直接替换表名即可运行
- 如果需要加筛选条件(比如只查指定成员、过滤特定时间段),直接在最外层加WHERE子句即可
内容的提问来源于stack exchange,提问作者kimphys
相关产品推荐
相关产品推荐

