[英]How can I find missing date range in sql server 2008?
我的數據如下所示。
如何從SS表中找到缺少的日期范圍。
我想在se_startdate和se_enddate之間找到缺少的(ss日期范圍)日期范圍。
例如上面。
缺少日期范圍是
2014-07-01 to 2014-07-06
2014-07-18 to 2014-07-30.
可能有一種更簡單的方法來執行此操作,但通常在嘗試查找丟失的數字/日期時,需要創建這些數字/日期,然后將LEFT JOIN
到現有數據中以查找丟失的內容。 您可以使用遞歸cte創建相關日期:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
SELECT *
FROM cal
然后,將LEFT JOIN
到表中以獲取缺少日期的列表:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
SELECT DISTINCT cal.dt
FROM cal
LEFT JOIN YourTable a
ON cal.dt BETWEEN CAST(SS_StartDate AS DATE) AND CAST(SS_EndDate AS DATE)
WHERE a.SS_StartDate IS NULL
然后,您需要使用DATEDIFF()
和ROW_NUMBER()
來找出連續的行是否屬於同一范圍,或者它們之間是否有間隔:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
,dt_list AS (SELECT DISTINCT cal.dt
FROM cal
LEFT JOIN YourTable a
ON cal.dt BETWEEN CAST(SS_StartDate AS DATE) AND CAST(SS_EndDate AS DATE)
WHERE a.SS_StartDate IS NULL)
SELECT dt
,DATEDIFF(D, ROW_NUMBER() OVER(ORDER BY dt), dt) AS dt_range
FROM dt_list
然后使用MIN()
和MAX()
獲得范圍:
WITH cal AS (SELECT CAST('2014-07-01' AS DATE) dt
UNION ALL
SELECT DATEADD(DAY,1,dt)
FROM cal
WHERE dt < '2014-07-30')
,dt_list AS (SELECT DISTINCT cal.dt
FROM cal
LEFT JOIN YourTable a
ON cal.dt BETWEEN CAST(SS_StartDate AS DATE) AND CAST(SS_EndDate AS DATE)
WHERE a.SS_StartDate IS NULL)
,dt_range AS (SELECT dt
,DATEDIFF(D, ROW_NUMBER() OVER(ORDER BY dt), dt) AS dt_range
FROM dt_list)
SELECT MIN(dt) AS BeginRange
,MAX(dt) AS EndRange
FROM dt_range
GROUP BY dt_range;
--OPTION (MAXRECURSION 0)
演示: SQL Fiddle
注意:如果您要檢查的范圍超過100天,則需要指定MAXRECURSION
,0表示沒有限制。
注2:如果您的SE
日期旨在推動完整的日期范圍,然后更改cal
從固定日期使用CTE來查詢MIN()
和MAX()
分別。
缺少的范圍必須從se_StartDate或ss_EndDate + 1開始。 同樣,它必須以se_EndDate或ss_StartDate-1結尾。 排列候選范圍並丟棄重疊部分。
此方法的優點是可以輕松地將時間精度調整為小時,分鍾或秒,而無需枚舉每個時鍾滴答。
SELECT DISTINCT
range_start, range_end, se_StartDate, se_EndDate
FROM MyTable t1
CROSS APPLY (
SELECT se_StartDate range_start
UNION ALL
SELECT DATEADD(day,1,SS_EndDate)
) rs
CROSS APPLY (
SELECT se_EndDate range_end
UNION ALL
SELECT DATEADD(day,-1,SS_StartDate)
FROM MyTable
WHERE
se_StartDate = t1.se_StartDate AND
se_EndDate = t1.se_EndDate AND
SS_StartDate > range_start
) re
WHERE NOT EXISTS (
SELECT 1
FROM MyTable
WHERE
range_start < SS_EndDate AND
range_end > SS_StartDate
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.