你不需要一个循环。你
永远不
应该用这种心态来处理SQL中的问题,它应该是最后的手段。
如果要处理日期问题,最简单的办法是使用
日历表
,如果你没有日历表,就创建一个,然后你可以直接使用。
DECLARE @StartDate DATE = '20150315',
@EndDate DATE = '20150305',
@BreakDate DATE = '20150310';
SELECT Date
FROM Calendar
WHERE Date <= @StartDate
AND Date > @EndDate
AND Date > @BreakDate;
然而,我知道创建一个日历表并不总是一种选择,但在飞行中生成一个日期列表是非常容易的。从以下文章中可以看出。
生成一个没有循环的集合或序列--第一部分
生成一个没有循环的集合或序列--第二部分
生成一个没有循环的集合或序列--第3部分
最好的方法是使用常数的交叉连接(在文章中被称为堆叠CTE)。这只是从一个10行的表值构造器开始,将其与自身交叉连接,得到100行,然后再得到100x100=10,000行,以此类推。
DECLARE @StartDate DATE = '20150315',
@EndDate DATE = '20150305',
@BreakDate DATE = '20150310';
WITH N1 (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
N4 (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N1.N) FROM N3 AS N1 CROSS JOIN N3 AS N2)
SELECT Date = DATEADD(DAY, 1 - N, @StartDate)
FROM N4
WHERE N <= DATEDIFF(DAY, @EndDate, @StartDate) + 1
AND N <= DATEDIFF(DAY, @BreakDate, @StartDate) + 1;
如果你的中断日期可以在开始日期之后,那么你只需要一个额外的逻辑来解决这个问题,这样你的查询就变成了。
DECLARE @StartDate DATE = '20150315',
@EndDate DATE = '20150305',
@BreakDate DATE = '20150310';
SELECT Date
FROM Calendar
WHERE Date <= @StartDate
AND Date > @EndDate
AND ( Date > @BreakDate
OR @BreakDate >= @StartDate
DECLARE @StartDate DATE = '20150315',
@EndDate DATE = '20150305',
@BreakDate DATE = '20150320';
WITH N1 (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
N4 (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N1.N) FROM N3 AS N1 CROSS JOIN N3 AS N2)
SELECT Date = DATEADD(DAY, 1 - N, @StartDate)
FROM N4
WHERE N <= DATEDIFF(DAY, @EndDate, @StartDate) + 1
AND ( N <= DATEDIFF(DAY, @BreakDate, @StartDate) + 1
OR @BreakDate >= @StartDate