【发布时间】:2025-12-28 14:20:15
【问题描述】:
我有一个相当大的数据集,其中包含人员及其保险的开始和结束日期。每个人可以有多个日期重叠的记录。我需要为每个人找到每个“岛屿”的起点和终点。
例如:
SKP_PERSON DATE_INSURANCE_START DATE_INSURANCE_END SKP_INSURANCE
1 1 7.11.2015 1.1.3000 1
2 1 7.11.2015 1.1.3000 2
3 2 10.4.2015 1.8.2016 23:59:59 3
4 3 28.3.2016 1.1.3000 4
5 4 5.12.2015 31.12.2015 23:59:59 5
6 4 5.12.2015 1.5.2016 23:59:59 6
7 4 1.2.2016 1.5.2016 23:59:59 7
8 5 15.1.2016 2.3.2016 23:59:59 8
9 5 15.3.2016 2.6.2016 23:59:59 9
我需要的结果是这样的:
SKP_PERSON DATE_INSURANCE_START DATE_INSURANCE_END
1 1 7.11.2015 1.1.3000
2 2 10.4.2015 1.8.2016 23:59:59
3 3 28.3.2016 1.1.3000
4 4 5.12.2015 1.5.2016 23:59:59
5 5 15.1.2016 2.3.2016 23:59:59
6 5 15.3.2016 2.6.2016 23:59:59
我设法通过将所有可能的日期(从 min(start) 到 max(end))加入每个人并找到每一天的滞后和领先值来找到解决方案 - 但记录和日期范围太多太大了,所以需要很长时间。有没有更有效的使用 PL/SQL 的解决方案?
编辑: 我试过的查询(简化):
WITH table1 AS (
SELECT d.dtime_day, COUNT(i.dkp_insurance), i.skp_person
FROM date d --a date table, contains a record for every day
JOIN insurance i ON d.dtime_day BETWEEN i.DATE_INSURANCE_START AND i.DATE_INSURANCE_END
GROUP BY d.dtime_day, i.skp_person
)
SELECT * FROM
(
SELECT distinct skp_person,
CASE WHEN LAG(dtime_day) OVER (PARTITION BY skp_person ORDER BY dtime_day) <> dtime_day -1 THEN dtime_day END AS start,
CASE WHEN LEAD(dtime_day) OVER (PARTITION BY skp_person ORDER BY dtime_day) <> dtime_day +1 THEN dtime_day END AS end
FROM table1 t1)
WHERE start IS NOT NULL OR end IS NOT NULL
ORDER BY skp_person
;
【问题讨论】:
-
你能提供你已经尝试过的SQL吗?另外,这些表上是否有任何索引?谢谢。
-
我不太确定我正在使用的数据仓库中的表是如何建立索引的——虽然 SKP_INSURANCE 是一个主键。我将在编辑中添加代码。
-
几个月前我回答了一个类似的问题,请看一下。从您编写的代码中,我看到您可以处理 SQL,您所需要的只是算法的想法(解决问题的方法);如果您认为可以使用我的解决方案,但需要进一步的帮助,请说出来。祝你好运! *.com/questions/36387048/…
-
查看您的样本数据,您可以在以不同方式处理开放区间 (end=1.1.3000) 时显着提高性能。
-
@mathguy:我将不得不对其进行正确测试,但看起来这可能正是我所需要的——我什至不需要更改任何内容,除了列名。非常感谢!