我有一张这样的表:
id start end
1 1-1-2015 29-1-2015
2 30-1-2015 28-2-2015
3 1-3-2015 30-3-2015
....
现在我需要sql
查询,该查询将检查end date
行和下一行start dat
e之间是否遗漏了任何日期。
E.g。如果end date
为29-1-2015
,那么下一行的start date
应该始终是该30-1-2015
的下一个日期。
如果错过了任何日期,则应该返回错误。
答案 0 :(得分:2)
您可以使用APPLY
获取下一条记录(假设您使用ID的顺序定义下一条记录),然后过滤掉下一条记录的开头与当前结尾不匹配的记录记录:
SELECT *
FROM YourTable AS T1
CROSS APPLY
( SELECT TOP 1 T2.[Start]
FROM YourTable AS T2
WHERE T2.ID > T1.ID
ORDER BY T2.ID
) AS NextStart
WHERE NextStart.[Start] != DATEADD(DAY, 1, T1.[End]);
如果您的ID列没有间隙,您可以使用连接:
SELECT *
FROM YourTable AS T1
INNER JOIN YourTable AS NextStart
ON T2.ID = T.ID + 1
WHERE NextStart.[Start] != DATEADD(DAY, 1, T.[End]);
如果一个句点的开头应该始终是前一个句点结束后的第二天,那么为什么不为此存储单个值。例如您需要存储的只有:
id start
1 2015-01-01
2 2015-01-30
3 2015-03-01
现在,您可以通过查找下一个开始日期来定义结束日期:
SELECT t.id,
t.start,
[end] = DATEADD(DAY, -1, e.start)
FROM dbo.YourTable AS t
OUTER APPLY
( SELECT TOP 1 start
FROM dbo.YourTable AS T2
WHERE t2.ID > t.ID
ORDER BY ID
) AS e;
如果您需要定期开始和结束,则可以将其设为视图,并确保您没有任何遗漏期。
答案 1 :(得分:0)
尝试使用简单的连接:
DECLARE @t TABLE ( id INT, s DATE, e DATE )
INSERT INTO @t
VALUES ( 1, '20150101', '20150129' ),
( 2, '20150130', '20150228' ),
( 3, '20150301', '20150330' ),
( 4, '20150501', '20150630' );
WITH cte
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY id ) AS id ,
s ,
e
FROM @t
)
SELECT c2.id ,
c1.id
FROM cte c1
JOIN cte c2 ON c2.id + 1 = c1.id
WHERE DATEADD(d, 1, c2.e) <> c1.s
输出:
id id
3 4
首先,您要使用连续数字对行进行编号。然后,您将加入下一行的行,并检查是否在prev行值中添加1天为您提供下一行值。
如果您已经连续CTE
,只需删除id
。