记录具有相邻开始日期(在Oracle 12中迄今为1天)的过滤器

时间:2018-09-07 11:07:03

标签: sql oracle date oracle12c

场景

  • 有CONTRACT表,其中包含对客户的引用
  • 每个客户可以拥有多个合同
  • 合同总会打开(VALID_FROM),有时会关闭(已填充VALID_TO)

对于每个客户,我都希望放弃所有续签的合同(一个合同已关闭,第二天又打开了-同一客户)

简化表格结构

CONTRACTS
    - ID (PK INTEGER)
    - CUSTOMER_ID (FK INTEGER NOT NULL)
    - VALID_FROM (DATE NOT NULL)
    - VALID_TO (DATE NULLABLE)

示例数据

ID|CUSTOMER_ID|VALID_FROM|VALID_TO
1|1|2018-01-01|2018-07-31
2|1|2018-11-01|NULL
3|2|2018-03-01|2018-04-30
4|2|2018-05-01|2018-11-30
5|3|2018-06-01|NULL

预期结果

ID|CUSTOMER_ID|VALID_FROM|VALID_TO
1|1|2018-01-01|2018-07-31
2|1|2018-11-01|NULL
4|2|2018-05-01|2018-11-30
5|3|2018-06-01|NULL

SQL

SELECT
  C.*
FROM CONTRACTS C
LEFT JOIN CONTRACTS C1 ON (C.CUSTOMER_ID=C1.CUSTOMER_ID AND *C.VALID_TO + 1 DAY*=C1.VALID_FROM)
WHERE C1.ID IS NULL

问题

我必须更改 C.VALID_TO + 1天,Oracle中正确的语法是什么?

1 个答案:

答案 0 :(得分:2)

您可以使用间隔类型明确表示要添加天数;

LEFT JOIN CONTRACTS C1
ON (C.CUSTOMER_ID=C1.CUSTOMER_ID AND C.VALID_TO + INTERVAL '1' DAY=C1.VALID_FROM)

或更简单地使用date arithmetic,只需从查询中删除单词“ DAY”即可。

SELECT
  C.*
FROM CONTRACTS C
LEFT JOIN CONTRACTS C1 ON (C.CUSTOMER_ID=C1.CUSTOMER_ID AND C.VALID_TO + 1=C1.VALID_FROM)
WHERE C1.ID IS NULL
ORDER BY C.CUSTOMER_ID, C.VALID_FROM;

        ID CUSTOMER_ID VALID_FROM VALID_TO  
---------- ----------- ---------- ----------
         1           1 2018-01-01 2018-07-31
         2           1 2018-11-01           
         4           2 2018-05-01 2018-11-30
         5           3 2018-06-01           

作为奖励,有两种替代方法;与其使用左联接,不如使用not exists

SELECT
  C.*
FROM CONTRACTS C
WHERE NOT EXISTS (
  SELECT *
  FROM CONTRACTS C1
  WHERE C.CUSTOMER_ID=C1.CUSTOMER_ID AND C.VALID_TO + 1=C1.VALID_FROM
)
ORDER BY C.CUSTOMER_ID, C.VALID_FROM;

或使用内联视图和分析型lead()调用,因此您只需要点击一次表即可:

SELECT ID, CUSTOMER_ID, VALID_FROM, VALID_TO
FROM (
  SELECT
    C.*,
    LEAD(VALID_FROM) OVER (PARTITION BY CUSTOMER_ID ORDER BY VALID_FROM) AS LEAD_VALID_FROM
  FROM CONTRACTS C
)
WHERE LEAD_VALID_FROM IS NULL OR VALID_TO + 1 != LEAD_VALID_FROM
ORDER BY CUSTOMER_ID, VALID_FROM;

两者与您的样本数据都得到相同的结果。

db<>fiddle demo of all four queries.