Oracle 中连续日期范围的分层查询

问题描述 投票:0回答:1

我正在尝试编写一个查询来获取会员的连续订阅日期,但无法拉取像下面这样的场景,其中会员的几个日期范围的 end_date 重叠,请帮助在 oracle 中提供逻辑/查询。

Data in the Table

身份证 开始日期 结束日期
12345 15 年 8 月 7 日 65 年 8 月 7 日
12345 2015 年 8 月 22 日 2016 年 1 月 1 日
12345 2016 年 3 月 24 日 66 年 3 月 23 日
12345 2016 年 7 月 6 日 2017 年 12 月 31 日
12345 2016 年 12 月 31 日 41 年 12 月 31 日
4662828 2015 年 8 月 22 日 2015 年 12 月 22 日
4662828 2016 年 1 月 1 日 2018 年 8 月 1 日
4662828 2017 年 6 月 10 日 2018 年 12 月 31 日
4662828 2018 年 12 月 1 日 72 年 12 月 4 日

Expected Data

身份证 开始日期 结束日期
12345 15 年 8 月 7 日 66 年 3 月 23 日
4662828 2015 年 8 月 22 日 2015 年 12 月 22 日
4662828 2016 年 1 月 1 日 72 年 12 月 4 日

以下是我正在使用的逻辑,但它没有给出预期的结果,请帮忙。

SELECT ID, START_DATE, END_DATE FROM (
    SELECT ID,CONNECT_BY_ROOT START_DATE START_DATE,DAYS_DIFF, END_DATE,PREV_END,CONNECT_BY_ISLEAF ISLEAF
    FROM ( SELECT ID,DAYS_DIFF,PREV_END, START_DATE,END_DATE   
        FROM (   SELECT ID,ROUND(START_DATE-PREV_END) DAYS_DIFF,
                    CASE WHEN START_DATE<=PREV_END THEN PREV_END END PREV_END, START_DATE,END_DATE
                FROM ( SELECT ID,LAG(END_DATE) OVER (PARTITION BY ID ORDER BY START_DATE) PREV_END, START_DATE,END_DATE  FROM TEST_TABLE A )                  
                  )     ) 
    CONNECT BY ID= PRIOR ID AND   PREV_END=  PRIOR END_DATE    START WITH PREV_END IS NULL  
) WHERE ISLEAF=1;  
sql oracle connect hierarchical
1个回答
0
投票

这是一个可以获得您预期结果的查询

``` 
WITH tmp AS
(
    SELECT 12345 AS id,     TO_DATE('07-Aug-15', 'DD/MON/YY') AS Start_date,    TO_DATE('07-Aug-65', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 12345 AS id,     TO_DATE('22-Aug-15', 'DD/MON/YY') AS Start_date,    TO_DATE('01-Jan-16', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 12345 AS id,     TO_DATE('24-Mar-16', 'DD/MON/YY') AS Start_date,    TO_DATE('23-Mar-66', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 12345 AS id,     TO_DATE('06-Jul-16', 'DD/MON/YY') AS Start_date,    TO_DATE('31-Dec-17', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 12345 AS id,     TO_DATE('31-Dec-16', 'DD/MON/YY') AS Start_date,    TO_DATE('31-Dec-41', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    
    SELECT 4662828 AS id,   TO_DATE('22-Aug-15', 'DD/MON/YY') AS Start_date,    TO_DATE('22-Dec-15', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 4662828 AS id,   TO_DATE('01-Jan-16', 'DD/MON/YY') AS Start_date,    TO_DATE('01-Aug-18', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 4662828 AS id,   TO_DATE('10-Jun-17', 'DD/MON/YY') AS Start_date,    TO_DATE('31-Dec-18', 'DD/MON/YY') AS End_date FROM dual UNION ALL
    SELECT 4662828 AS id,   TO_DATE('01-Dec-18', 'DD/MON/YY') AS Start_date,    TO_DATE('04-Dec-72', 'DD/MON/YY') AS End_date FROM dual 
)
, tmp1 AS
(
    SELECT 
        CONNECT_BY_ROOT t.start_date AS start_date,
        t.id,
        t.start_date AS start_date1,
        t.end_date,
        level AS lvl
    FROM tmp t
    CONNECT BY PRIOR id = id AND PRIOR start_date <> start_date AND PRIOR end_date <> end_date 
        AND PRIOR end_date >= start_date AND PRIOR end_date < end_date
)
, tmp2 AS 
(
    SELECT *
    FROM tmp1
    WHERE (start_date, id, lvl) IN
        (
            SELECT start_date, id, MAX(lvl)
            FROM tmp1
            GROUP BY start_date, id
        )
)
SELECT id,
    MIN(start_date) AS start_date,
    end_date
FROM tmp2
GROUP BY id, end_date
ORDER BY id, start_date;
| ID | START\_DATE | END\_DATE |
| --:|:----------|:--------|
| 12345 | 07-AUG-15 | 23-MAR-66 |
| 4662828 | 22-AUG-15 | 22-DEC-15 |
| 4662828 | 01-JAN-16 | 04-DEC-72 |

[fiddle](https://dbfiddle.uk/VGbdPntE)
© www.soinside.com 2019 - 2024. All rights reserved.