如何使用Oracle分析函数查询任务时间范围内的重复日期?
找出同一任务和医生下的重复覆盖日期
输入表
| Task# | Doctor | FromDay | ToDay |
|---|---|---|---|
| 1 | Bar | 3 | 7 |
| 1 | Bar | 6 | 8 |
| 2 | Bar | 1 | 3 |
| 2 | Bar | 2 | 9 |
| 3 | Bar | 1 | 2 |
| 3 | Bar | 6 | 7 |
需求说明
提取同一Task#和Doctor下,被多个时间区间重复覆盖的日期,最终输出格式如下:
期望输出
| Task# | Doctor | Day |
|---|---|---|
| 1 | Bar | 6 |
| 1 | Bar | 7 |
| 2 | Bar | 2 |
| 2 | Bar | 3 |
解决方案思路
- 为每个时间区间生成包含所有日期的序列;
- 按
Task#、Doctor、Day分组,统计每个日期的覆盖次数; - 筛选出覆盖次数≥2的日期,即为重复覆盖的目标日期。
SQL实现(Oracle环境)
WITH date_ranges AS ( SELECT Task#, Doctor, FromDay + LEVEL - 1 AS Day FROM your_table CONNECT BY LEVEL <= ToDay - FromDay + 1 AND PRIOR Task# = Task# AND PRIOR Doctor = Doctor AND PRIOR SYS_GUID() IS NOT NULL -- 避免多区间产生笛卡尔积 ), date_counts AS ( SELECT Task#, Doctor, Day, COUNT(*) AS occurrence FROM date_ranges GROUP BY Task#, Doctor, Day ) SELECT Task#, Doctor, Day FROM date_counts WHERE occurrence >= 2 ORDER BY Task#, Day;
代码解释
- date_ranges CTE:借助Oracle的
CONNECT BY语法,为每个FromDay到ToDay的区间生成完整的日期序列,PRIOR SYS_GUID() IS NOT NULL用于确保每个独立区间生成自身的日期序列,避免交叉循环。 - date_counts CTE:对每个任务、医生维度下的日期进行计数,统计每个日期被不同区间覆盖的次数。
- 最终筛选出覆盖次数≥2的日期,即为重复覆盖的目标日期,按任务号和日期排序输出。
其他数据库适配说明
如果使用非Oracle数据库,生成日期序列的方式需调整:
- PostgreSQL:用
generate_series(FromDay, ToDay)替代CONNECT BY生成日期序列; - MySQL 8.0+:用递归CTE来生成连续日期序列。
内容的提问来源于stack exchange,提问作者OracleDBACurios
相关产品推荐
相关产品推荐

