查找跨越记录的日期范围之间的差距

时间:2020-03-30 15:01:06

标签: sql oracle

我正在尝试编写一个查询,以便在传递两个日期时可以找到给定SELECT CASE WHEN COUNT(DISTINCT Name) = 2 THEN 'Yes' ELSE 'No' END AS result FROM [dbo].[Notification] WHERE Name IN ('Game', 'Gamer') 的日期范围内的任何空白。

编辑:我需要知道我的日期范围中是否存在全部空白或部分空白。

我有以下格式的数据:

ID

NB。结束日期为null实质上意味着“直到当前日期仍然有效”。

例如Example 1: | ID | START_DATE | END_DATE | |----|------------|------------| | 1 | 01/01/2019 | 30/09/2019 | | 1 | 01/03/2020 | (null) | Example 2: | ID | START_DATE | END_DATE | |----|------------|------------| | 2 | 01/01/2019 | 30/09/2019 | | 2 | 01/10/2019 | 01/12/2019 | | 2 | 02/12/2019 | (null) | 与2019年9月30日至2020年1月3日之间的间隔为152天。如果我在Example 1的范围内查询,则该范围内没有差距。而如果我查看的是日期范围05/05/2019 - 01/09/2019,则该范围有一天的间隔。

对于它的价值,我实际上不在乎有多少天的间隔,而只是在乎是否存在。

我已经尝试过类似的操作,但是当我的约会陷入空白时,它是行不通的:

05/05/2019 - 02/10/2019

SELECT SUM(START_DATE - PREV_END - 1) FROM ( SELECT ID, START_DATE, END_DATE, LAG(END_DATE) OVER (ORDER BY START_DATE) AS PREV_END_DATE FROM TBL WHERE ID = X_ID ) WHERE START_DATE >= Y_FIRST_DATE AND START_DATE <= Z_SECOND_DATE; X_IDY_FIRST_DATE只是我可能想要传递的任何其他ID或日期范围。

我该怎么办?

4 个答案:

答案 0 :(得分:1)

确定日期的另一种方法可能是使用SELECT .. FROM dual CONNECT BY LEVEL <=语法,通过EXIST间隔INTERSECT划分两组,一个找到极值参数之间的所有日期,另一个找到所有日期。符合插入表中日期的日期范围内的日期:

SELECT CASE WHEN 
       SUM( 1 + LEAST(Z_SECOND_DATE,NVL(END_DATE,TRUNC(SYSDATE))) 
         - GREATEST(Y_FIRST_DATE,START_DATE) ) = Z_SECOND_DATE - Y_FIRST_DATE + 1 THEN
           'NO Gap'
       ELSE
           'Gap Exists'  
       END "gap?"
  FROM TBL t
 WHERE ID = X_ID
   AND EXISTS ( SELECT Y_FIRST_DATE + LEVEL - 1
                  FROM dual
               CONNECT BY LEVEL <= Z_SECOND_DATE - Y_FIRST_DATE + 1 
               INTERSECT
                SELECT t.START_DATE + LEVEL - 1
                  FROM dual
               CONNECT BY LEVEL <= NVL(t.END_DATE,TRUNC(SYSDATE))- t.START_DATE + 1
               )    
根据示例数据,

START_DATE的值假定为非空。

Demo

答案 1 :(得分:1)

这是孤岛和缺口问题的另一个变体,在这里经常出现。我认为这符合Oracle的模式匹配功能。举个例子:

WITH tbl AS
(
  SELECT 1 AS ID, to_date('01/01/2019', 'DD/MM/YYYY') AS START_DATE, to_date('30/09/2019', 'DD/MM/YYYY') AS END_DATE FROM DUAL
  UNION ALL
  SELECT 1 AS ID, to_date('01/03/2020', 'DD/MM/YYYY') AS START_DATE, NULL AS END_DATE FROM DUAL
  UNION ALL
  SELECT 2 AS ID, to_date('01/01/2019', 'DD/MM/YYYY') AS START_DATE, to_date('30/09/2019', 'DD/MM/YYYY') AS END_DATE FROM DUAL
  UNION ALL
  SELECT 2 AS ID, to_date('01/10/2019', 'DD/MM/YYYY') AS START_DATE, to_date('01/12/2019', 'DD/MM/YYYY') AS END_DATE FROM DUAL
  UNION ALL
  SELECT 2 AS ID, to_date('02/12/2019', 'DD/MM/YYYY') AS START_DATE, NULL AS END_DATE FROM DUAL
)
SELECT *
FROM tbl
MATCH_RECOGNIZE(ORDER BY ID, start_date
                MEASURES b.id AS ID,
                         a.end_date+1 AS GAP_START,
                         b.start_date-1 AS GAP_END
                PATTERN (A B+)
                DEFINE B AS start_date > PREV(end_date)+1 AND ID = PREV(ID))L;

我知道它看起来很长,但是大多数都在创建WITH子句。模式匹配使您可以定义间隙,并相应地提取信息。请注意,为了留出间隔,您的开始日期必须大于前一个结束日期+由ID列分组的1。

要增强此功能以回答更新/编辑的问题,只需将以下代码行添加到末尾:

WHERE GREATEST(gap_start, TO_DATE('15/09/2019', 'DD/MM/YYYY' /*Y_FIRST_DATE*/)) <= LEAST(gap_end, to_date('15/10/2019', 'DD/MM/YYYY')/*Z_SECOND_DATE*/)

答案 2 :(得分:0)

您可以将传递的日期范围划分为日期,然后将其与表格中的日期范围进行比较,如下所示:

SELECT
    CASE WHEN SUM(CASE WHEN T.ID IS NULL THEN 1 END) > 0 
         THEN 'THERE IS GAP'
         ELSE 'THERE IS NO GAP'
    END AS RESULT_
FROM ( SELECT P_IN_FROM_DATE + LEVEL - 1 AS CUST_DATES
         FROM DUAL
        CONNECT BY LEVEL <= P_IN_TO_DATE - P_IN_FROM_DATE + 1
    ) CUST_TBL
    LEFT JOIN TBL T 
    ON CUST_TBL.CUST_DATES BETWEEN T.START_DATE AND T.END_DATE
       OR ( CUST_TBL.CUST_DATES >= T.START_DATE AND T.END_DATE IS NULL )

答案 3 :(得分:0)

我建议在当前记录之前 前找到最大结束日期-根据开始日期。

那将是:

select t.*
from (select t.*,
             max(end_date) over (order by start_date
                                 rows between unbounded preceding and 1 preceding
                                ) as max_prev_end_date
      from tbl t
      where start_date <= :input_end_date and
            end_date >= :input_start_date
     ) t
where max_prev_end_date < start_date;
相关问题