1

我有一张这样的桌子:

Id    Begin_Date    End_date    
1     01-JAN-12     05-JAN-12
1     01-FEB-12     01-MAR-12
1     15-FEB-12     05-MAR-12

对于给定的 ID,它给出了一组日期范围。假设如果日期介于该 ID 的开始日期和结束日期之间,则该 ID 为“on”。否则,“关闭”

这里的问题是最后两行——日期范围重叠并相互矛盾。第二行声称 1 在 01-FEB-12 和 01-MAR-123 之间“开启”,但第三行声称 1 在 2012 年 2 月 14 日之前关闭。同样,第二行声称 1 在 2012 年 3 月 2 日关闭,但第 3 行声称它已打开。

我想应用的和解逻辑是,在出现矛盾的情况下,选择最早的开始日期和之后的最早的结束日期。因此,结果将是:

Id    Begin_Date    End_date    
1     01-JAN-12     05-JAN-12
1     01-FEB-12     01-MAR-12

我能够使用滞后分析功能来解决这个问题,但我在其他用例中遇到了困难。取这个输入数据集。

Id    Begin_Date    End_date    
1     01-JAN-12     10-JAN-12
1     5-JAN-12      8-JAN-12
1     12-JAN-12     15-JAN-12
1     1-JAN-12      14-JAN-12

我在这里期望的输出是:

Id    Begin_Date    End_date    
1     01-JAN-12     8-JAN-12
1     01-JAN-12     14-JAN-12

...因为第一行是最早的开始日期,而其结束日期是之后最早的结束日期。下一行是上一个结束日期之后的最早开始日期,该行的结束日期是之后最早的结束日期。12 年 1 月 14 日之后没有开始日期,所以我完成了。

我解决这个问题的运气很差。我尝试的一种方法是按 id 划分排名并将其与最大排名进行比较。然后我使用滞后函数与之前的排名进行比较。但是,对于上述用例,此策略完全失败。

有什么建议么?

4

2 回答 2

3

好吧,关键要求在于:

我想应用的和解逻辑是,在出现矛盾的情况下,选择最早的开始日期和之后的最早的结束日期。

sqlfiddle在这里

CREATE TABLE table1
(
  id INT,
  DateStart DATE,
  DateEnd DATE
);

INSERT INTO table1
VALUES
(1, TO_DATE('20110101','YYYYMMdd'), TO_DATE('20110110','YYYYMMdd'));
INSERT INTO table1
VALUES
(2, TO_DATE('20110105','YYYYMMdd'), TO_DATE('20110108','YYYYMMdd'));
INSERT INTO table1
VALUES
(3, TO_DATE('20110112','YYYYMMdd'), TO_DATE('20110115','YYYYMMdd'));
INSERT INTO table1
VALUES
(4, TO_DATE('20110101','YYYYMMdd'), TO_DATE('20110114','YYYYMMdd'));
INSERT INTO table1
VALUES
(5, TO_DATE('20110206','YYYYMMdd'), TO_DATE('20110208','YYYYMMdd'));
INSERT INTO table1
VALUES
(6, TO_DATE('20110201','YYYYMMdd'), TO_DATE('20110207','YYYYMMdd'));

选择语句:

SELECT ID, DATESTART, DATEEND
FROM 
(
  SELECT ID, TYPE, DATES AS DATESTART, 
         LEAD(DATES) OVER (ORDER BY DATES) AS DATEEND
  FROM
  (
    SELECT ID, TYPE,DATES,
      LAG(ID) OVER (ORDER BY DATES) AS LASTID,
      LAG(TYPE) OVER (ORDER BY DATES) AS LASTTYPE,
      LAG(DATES) OVER (ORDER BY DATES) AS LASTDATES
    FROM
    (
      SELECT ID,'START' AS TYPE,DATESTART AS DATES
      FROM table1
      UNION ALL
      SELECT ID,'END',DATEEND
      FROM table1
    )
  ) H
  WHERE TYPE != LASTTYPE OR LASTTYPE IS NULL
)
WHERE TYPE = 'START'
ORDER BY DATESTART

以下是每个子查询的分步说明:

  1. 将每一行date start分解date end为一列

  2. 使用复制最后一行LAG并将其放入当前行

  3. 过滤掉中间的行(例如 1,2,3,4 删除 2,3)

    在下一行中获取结束日期,因为这些是第一行或最后一行

  4. 只提取有用的行,那些行TYPE = START

于 2012-11-02T11:39:40.663 回答
1

对于第二个数据集:

Id    Begin_Date    End_date    
1     01-JAN-12     10-JAN-12
1     5-JAN-12      8-JAN-12
1     12-JAN-12     15-JAN-12
1     1-JAN-12      14-JAN-12

在您的对帐逻辑之后,结果将是:

Id    Begin_Date    End_date    
1     01-JAN-12     8-JAN-12 (includes the rows 1,2 and 4 -> minimum begin_date is 1-JAN, minimum end_date is 8-JAN)
1     12-JAN-12     15-JAN-12 (includes row 3)
于 2012-11-02T09:21:49.117 回答