我正在尝试编写一个查询,以便在传递两个日期时可以找到给定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_ID
和Y_FIRST_DATE
只是我可能想要传递的任何其他ID或日期范围。
我该怎么办?
答案 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
的值假定为非空。
答案 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;