【问题标题】:How to identify overlapping rows如何识别重叠行
【发布时间】:2020-12-27 05:06:21
【问题描述】:

我需要识别重叠的行。下面是表格,我需要列重叠:

| identifier    | status    | startDate     | endDate       | pID   | OVERLAPPING   |
|------------   |---------- |------------   |------------   |-----  |-------------  |
| A             | Approved  | 2020-10-01    | 2020-10-07    | x1    | Yes           |
| A             | Approved  | 2020-10-01    | 2020-10-07    | x2    | No            |
| A             | Approved  | 2020-10-01    | 2020-10-07    | x3    | Yes           |
| A             | Approved  | 2020-10-01    | 2020-10-07    | x4    | No            |
| B             | Approved  | 2020-10-10    | 2020-10-12    | x2    | No            |
| B             | Approved  | 2020-10-10    | 2020-10-12    | x5    | No            |
| C             | Rejected  | 2020-10-05    | 2020-10-06    | x3    | No            |
| C             | Rejected  | 2020-10-05    | 2020-10-06    | x7    | No            |
| C             | Rejected  | 2020-10-05    | 2020-10-06    | x8    | No            |
| C             | Rejected  | 2020-10-05    | 2020-10-06    | x9    | No            |
| D             | Approved  | 2020-10-01    | 2020-10-07    | x5    | No            |
| D             | Approved  | 2020-10-01    | 2020-10-07    | x1    | Yes           |
| E             | Approved  | 2020-10-03    | 2020-10-04    | x3    | Yes           |
  1. 由于 C 处于拒绝状态,因此任何具有 C 标识符的内容都不会被计入查找重叠行。因此即使 C 中的坚韧 x3 与 A 中的 x3 重叠,也不会被视为重叠。
  2. x1 在 A 和 D 中重叠。因此这两行都将被计为重叠。
  3. A 中的 x3 与 E 中的 x3 重叠,因为 E 的开始日期和结束日期在 A 的周期内。
  4. B 和 D 中的 x5 不重叠,因为 B 和 D 的日期不重叠。

如果开始日期和结束日期相同,我可以通过创建一个由开始日期、结束日期和 pID 组合而成的列,然后计算所有行的该字段来获得此信息。如果它大于 1,那么我标记重叠。但这不包括 x3 的场景,其中开始日期和日期不相同但在一段时间内仍然重叠。

【问题讨论】:

  • Redshift 还是 Postgres?虽然它们有一些古老的根源,但它们是截然不同的产品

标签: sql date amazon-redshift


【解决方案1】:

这样的?

(如果一行与其他行重叠,我使用相关子查询来避免连接返回多行。)

SELECT
  *,
  (
    SELECT 1
      FROM yourTable AS lookup
     WHERE lookup.identifier <> yourTable.identifier  -- Don't check overlaps with itself
       AND lookup.pID         = yourTable.pID
       AND lookup.startDate  <= yourTable.endDate
       AND lookup.endDate    >= yourTable.startDate
     LIMIT 1
  )
FROM
  yourTable

注意&gt;=&lt;=,这取决于您使用的是包容性(我希望不是)还是排他性(我希望如此)endDate

【讨论】:

  • 使用CASE WHEN EXISTS(...) THEN 1 ELSE 0 END 可能比SELECT 1 ... LIMIT 1 更有效。
  • @GMB - 我认为 RedShift 只允许 EXISTS() 并返回布尔类型。
  • 是的,打字更短:)
【解决方案2】:

根据你的叙述,这似乎符合你的逻辑:

select *,
   case 
     when status = 'Rejected' then 'No'
       -- previous row overlaps
     when startDate < -- maybe <=
          max(case when status <> 'Rejected' then endDate end)
          over (partition by pID
                order by startDate, endDate desc
                rows between unbounded preceding and 1 preceding)
       -- next row overlaps
       or endDate > -- maybe >=
          min(case when status <> 'Rejected' then startDate end)
          over (partition by pID
                order by startDate, endDate desc
                rows between 1 following and unbounded following)
     then 'Yes'
     else 'No'
   end 
from tab

【讨论】:

    【解决方案3】:

    试试这个(虽然我使用了一个布尔值与真假...

    WITH
    input(identifier,status,startDate,endDate,pID,OVERLAPPING) AS (
              SELECT 'A','Approved',DATE '2020-10-01',DATE '2020-10-07','x1','Yes'
    UNION ALL SELECT 'A','Approved',DATE '2020-10-01',DATE '2020-10-07','x2','No'
    UNION ALL SELECT 'A','Approved',DATE '2020-10-01',DATE '2020-10-07','x3','Yes'
    UNION ALL SELECT 'A','Approved',DATE '2020-10-01',DATE '2020-10-07','x4','No'
    UNION ALL SELECT 'B','Approved',DATE '2020-10-10',DATE '2020-10-12','x2','No'
    UNION ALL SELECT 'B','Approved',DATE '2020-10-10',DATE '2020-10-12','x5','No'
    UNION ALL SELECT 'C','Rejected',DATE '2020-10-05',DATE '2020-10-06','x3','No'
    UNION ALL SELECT 'C','Rejected',DATE '2020-10-05',DATE '2020-10-06','x7','No'
    UNION ALL SELECT 'C','Rejected',DATE '2020-10-05',DATE '2020-10-06','x8','No'
    UNION ALL SELECT 'C','Rejected',DATE '2020-10-05',DATE '2020-10-06','x9','No'
    UNION ALL SELECT 'D','Approved',DATE '2020-10-01',DATE '2020-10-07','x5','No'
    UNION ALL SELECT 'D','Approved',DATE '2020-10-01',DATE '2020-10-07','x1','Yes'
    UNION ALL SELECT 'E','Approved',DATE '2020-10-03',DATE '2020-10-04','x3','Yes'
    )
    SELECT 
      *
    , status = 'Approved'
      AND (
         COALESCE(LAG(enddate)    OVER(w) ,'0001-01-01')> startdate
      OR COALESCE(LEAD(startdate) OVER(w) ,'9999-12-31')< enddate
      ) AS overlap
    FROM input
    WINDOW w AS (PARTITION BY pid ORDER BY startdate)
    ORDER BY
      identifier
    , startdate
    ;
    -- out identifier|status  |startDate |endDate   |pID|OVERLAPPING|overlap
    -- out A         |Approved|2020-10-01|2020-10-07|x3 |Yes        |true
    -- out A         |Approved|2020-10-01|2020-10-07|x2 |No         |false
    -- out A         |Approved|2020-10-01|2020-10-07|x4 |No         |false
    -- out A         |Approved|2020-10-01|2020-10-07|x1 |Yes        |true
    -- out B         |Approved|2020-10-10|2020-10-12|x5 |No         |false
    -- out B         |Approved|2020-10-10|2020-10-12|x2 |No         |false
    -- out C         |Rejected|2020-10-05|2020-10-06|x3 |No         |false
    -- out C         |Rejected|2020-10-05|2020-10-06|x8 |No         |false
    -- out C         |Rejected|2020-10-05|2020-10-06|x7 |No         |false
    -- out C         |Rejected|2020-10-05|2020-10-06|x9 |No         |false
    -- out D         |Approved|2020-10-01|2020-10-07|x1 |Yes        |true
    -- out D         |Approved|2020-10-01|2020-10-07|x5 |No         |false
    -- out E         |Approved|2020-10-03|2020-10-04|x3 |Yes        |true
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-22
      • 1970-01-01
      • 2017-01-31
      • 1970-01-01
      • 2012-09-26
      相关资源
      最近更新 更多