【问题标题】:how to find which rows are being overlap while finding overlap b/w the dates如何在查找日期之间的重叠时查找哪些行正在重叠
【发布时间】:2020-11-11 20:07:25
【问题描述】:

我们如何找到日期之间的重叠圈。重叠意味着当开始日期和结束日期在以下示例的相同范围内时,第 1 行没有重叠。第 2 到 5 行可以被视为一组重叠,因为开始日期和结束日期与它们自己重叠第 6 行和第 7 行可以被视为一组重叠,例如。第 6 行和第 7 行 --> 第 7 行的开始日期与第 6 行的结束日期在同一范围内,因此它成为重叠

一旦发现重叠,则需要找出 min(start date) 和 max(end date) 和 想要为每个重叠分配一个唯一的 id,并且在 S.NO 列中应该显示哪些行重叠。

下面是 I/p 和 O/p

【问题讨论】:

    标签: sql oracle oracle11g


    【解决方案1】:

    基于this answer(其中包含查询的详细说明),您可以更改最后部分以生成重叠行组,然后使用LISTAGG聚合以获得分隔的sno值:

    SELECT id,
           MIN( dt ) AS start_date,
           MAX( dt ) AS end_date,
           LISTAGG( CASE value WHEN 1 THEN sno END, ',' )
             WITHIN GROUP ( ORDER BY dt ) AS snos
    FROM   (
      SELECT sno,
             id,
             dt,
             value,
             SUM( start_end ) OVER ( ORDER BY dt ASC, value DESC )
               AS grp
      FROM   (
        SELECT sno,
               id,
               dt,
               value,
               CASE SUM( value ) OVER ( ORDER BY dt ASC, value DESC, ROWNUM ) * value
               WHEN 1 THEN 1
               WHEN 0 THEN 0
               ELSE NULL
               END AS start_end
        FROM   table_name
        UNPIVOT ( dt FOR value IN ( start_date AS 1, end_date AS -1 ) )
      )
    )
    GROUP BY id, grp;
    

    其中,对于样本数据:

    CREATE TABLE table_name ( sno, id, start_date, end_date ) AS
    SELECT 1, 1, DATE '2020-10-11', DATE '2020-10-11' FROM DUAL UNION ALL
    SELECT 2, 1, DATE '2020-11-04', DATE '2020-12-11' FROM DUAL UNION ALL
    SELECT 3, 1, DATE '2020-11-05', DATE '2020-11-10' FROM DUAL UNION ALL
    SELECT 4, 1, DATE '2020-11-06', DATE '2020-11-10' FROM DUAL UNION ALL
    SELECT 5, 1, DATE '2020-11-20', DATE '2020-12-20' FROM DUAL UNION ALL
    SELECT 6, 1, DATE '2021-01-01', DATE '2021-01-20' FROM DUAL UNION ALL
    SELECT 7, 1, DATE '2021-01-01', DATE '2021-03-25' FROM DUAL;
    

    输出:

    身份证 | START_DATE | END_DATE | SNOS -: | :----------------- | :----------------- | :------ 1 | 2020-10-11 00:00:00 | 2020-10-11 00:00:00 | 1 1 | 2020-11-04 00:00:00 | 2020-12-20 00:00:00 | 2,3,4,5 1 | 2021-01-01 00:00:00 | 2021-03-25 00:00:00 | 6,7

    db小提琴here


    从 Oracle 12c 开始,您可以使用 MATCH_RECOGNIZE 进行更简单的查询:

    SELECT id,
           MIN( start_date ) AS start_date,
           MAX( end_date )   AS end_date,
           LISTAGG( sno, ',' ) WITHIN GROUP ( ORDER BY start_date ASC, END_DATE ASC )
             AS snos
    FROM   table_name
    MATCH_RECOGNIZE (
      PARTITION BY id
      ORDER     BY start_date ASC, end_date ASC
      MEASURES  MATCH_NUMBER() AS grp
      ALL ROWS PER MATCH
      PATTERN ( OVERLAPPING_DATES* LAST_DATE )
      DEFINE OVERLAPPING_DATES AS NEXT( start_date ) <= MAX( end_date )
    )
    GROUP BY id, grp
    

    db小提琴here

    【讨论】:

    • 感谢 MTO,但 unpivot 的操作成本会更高一些,我可以使用除 s.no 之外的分析函数来实现此结果,因为在您的情况下,我没有像 START_END 这样的任何变量。在不使用 START_END 变量的情况下,还有其他方法可以实现 S.no
    【解决方案2】:

    这是一种孤岛问题。您可以使用累积最大值来确定是否存在重叠来解决此问题。然后累积总和和聚合做你想要的:

    select id, min(start_date), max(end_date),
           listagg(s_no, ',') within group (order by s_no) as s_nos
    from (select t.*,
                 sum(case when prev_end_date >= start_date then 0 else 1 end) over (partition by id order by s_no) as grp
          from (select t.*,
                       max(end_date) over (
                           partition by id
                           order by s_no
                           rows between unbounded preceding and 1 preceding
                          ) as prev_end_date
                from t
               ) t
         ) t
    group by id, grp;
    

    Here 是一个 dbfiddle。

    【讨论】:

    • @Tejash 。 . .现在可以了。
    猜你喜欢
    • 1970-01-01
    • 2020-02-19
    • 2010-10-15
    • 2021-06-19
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多