sql - 合并重叠日期的记录
问题描述
我有如下数据,想合并重叠日期的记录。重叠记录的开始和结束日期的 MIN 和 MAX 应该是合并记录的开始和结束日期。
合并前:
Item Code Start_date End_date
============== =========== ===========
111 15-May-2004 20-Jun-2004
111 22-May-2004 07-Jun-2004
111 20-Jun-2004 13-Aug-2004
111 27-May-2004 30-Aug-2004
111 02-Sep-2004 23-Dec-2004
222 21-May-2004 19-Aug-2004
所需输出:
Item Code Start_date End_date
============== =========== ===========
111 15-May-2004 30-Aug-2004
111 02-Sep-2004 23-Dec-2004
222 21-May-2004 19-Aug-2004
您可以使用创建示例数据
create table item(item_code number, start_date date, end_date date);
insert into item values (111,to_date('15-May-2004','DD-Mon-YYYY'),to_date('20-Jun-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('22-May-2004','DD-Mon-YYYY'),to_date('07-Jun-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('20-Jun-2004','DD-Mon-YYYY'),to_date('13-Aug-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('27-May-2004','DD-Mon-YYYY'),to_date('30-Aug-2004','DD-Mon-YYYY'));
insert into item values (111,to_date('02-Sep-2004','DD-Mon-YYYY'),to_date('23-Dec-2004','DD-Mon-YYYY'));
insert into item values (222,to_date('21-May-2004','DD-Mon-YYYY'),to_date('19-Aug-2004','DD-Mon-YYYY'));
commit;
解决方案
这类问题的代码相当棘手。这是一种效果很好的方法:
with item (item_code, start_date, end_date) as (
select 111,to_date('15-05-2004','DD-MM-YYYY'),to_date('20-06-2004','DD-MM-YYYY') from dual union all
select 111,to_date('22-05-2004','DD-MM-YYYY'),to_date('07-06-2004','DD-MM-YYYY') from dual union all
select 111,to_date('20-06-2004','DD-MM-YYYY'),to_date('13-08-2004','DD-MM-YYYY') from dual union all
select 111,to_date('27-05-2004','DD-MM-YYYY'),to_date('30-08-2004','DD-MM-YYYY') from dual union all
select 111,to_date('02-09-2004','DD-MM-YYYY'),to_date('23-12-2004','DD-MM-YYYY') from dual union all
select 222,to_date('21-05-2004','DD-MM-YYYY'),to_date('19-08-2004','DD-MM-YYYY') from dual
),
id as (
select item_code, start_date as dte, count(*) as inc
from item
group by item_code, start_date
union all
select item_code, end_date, - count(*) as inc
from item
group by item_code, end_date
),
id2 as (
select id.*, sum(inc) over (partition by item_code order by dte) as running_inc
from id
),
id3 as (
select id2.*, sum(case when running_inc = 0 then 1 else 0 end) over (partition by item_code order by dte desc) as grp
from id2
)
select item_code, min(dte) as start_date, max(dte) as end_date
from id3
group by item_code, grp;
和一个rextester来验证它。
这是在做什么?好问题。这些问题的想法是定义相邻的组。此方法通过计算到给定日期的“开始”和“结束”的数量来实现。当值为 0 时,一个组结束。
具体步骤如下:
(1) 将所有日期与日期是开始日期还是结束日期一起分成单独的行。该指标是定义范围的关键——+1 表示“进入”,“-1”表示退出。
(2) 计算指标的累计。此总数中的 0 是重叠范围的末端。
(3) 对 0 进行反向累积和以识别组。
(4) 聚合得到最终结果。
您可以查看每个 CTE 以了解数据中发生的情况。
推荐阅读
- java - java.lang.IllegalArgumentException:日志标记“okhttp3.mockwebserver.MockWebServer”超过 23 个字符的限制
- javascript - 为什么 window.btoa 不能处理 Javascript 中的“-”字符?
- node.js - 在 postgres 中插入或更新时,我得到 Parser.parseErrorMessage
- java - Spring MongoRepository Null 和 isNull 的区别
- java - Android viewGroup 问题 - 使用 Appium 进行测试
- payment-gateway - 如何修复 Cashfree 支付网关签名不匹配错误?
- python - 根据Python中的创建日期对文件列表进行排序
- javascript - Binance Rest API JSON 转 HTML
- python - 学习 LM 教程时出现内存问题
- html - 使用 CSS 的相对缩进