可能有一种更简单的方法来执行此操作,但通常在尝试查找丢失的数字/日期时,您需要创建这些数字/日期,然后 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() 的查询。