我需要一个日期递减的SQL查询循环。
StartDate : 3/15/2015 [Date param] [MM/dd/yyyy]
EndDate : 3/5/2015 [Date param]
Operation : Decrement by a day toward EndDate
BreakDate : 3/10/2015 [Date param]
当前日期(循环中)应从开始日期到结束日期打印一天减量
如果达到中断日期,那么循环应该自行停止[内循环]
输入上面的示例结果:
3/15/2015
3/14/2015
3/13/2015
3/11/2015
3/10/2015
请帮助。
答案 0 :(得分:5)
您不需要循环。您应该从不以这种心态处理SQL中的问题,它应该是最后的手段。
如果使用日期,那么最简单的解决方案是使用calendar table,如果你没有创建一个,那么你可以使用:
DECLARE @StartDate DATE = '20150315',
@EndDate DATE = '20150305',
@BreakDate DATE = '20150310';
SELECT Date
FROM Calendar
WHERE Date <= @StartDate
AND Date > @EndDate
AND Date > @BreakDate;
但是,我很欣赏创建日历表并不总是一个选项,但可以很容易地生成日期列表。来自以下文章:
动态执行此操作的最佳方法是使用常量的交叉连接(文章中称为Stacked 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
);
答案 1 :(得分:2)
此解决方案限制为2048天,但可以使用不同的计数进行扩展:
SELECT cast(dateadd(day, -number, @startdate) as date) date
FROM master..spt_values
WHERE
type = 'P'
AND dateadd(day, -number, @StartDate) >= @EndDate
AND @BreakDate NOT BETWEEN dateadd(day, 1 - number, @StartDate) AND @startdate
答案 2 :(得分:1)
作业? ;)
DECLARE @dateStart SMALLDATETIME = '20150315'
DECLARE @dateEnd SMALLDATETIME = '20150305'
DECLARE @dateBreak SMALLDATETIME = '20150310'
WHILE (@dateStart>@dateEnd)
BEGIN
print @dateStart;
IF (@dateStart=@dateBreak) BREAK
SET @dateStart-=1
END
答案 3 :(得分:0)
您可以通过WHILE
循环执行此操作。但在开始循环之前,请考虑RBAR。
这将按预期给出准确的输出。
DECLARE @FromDate DATE = '3/15/2015',
@EndDate DATE = '3/5/2015',
@BreakDate DATE = '3/10/2015'
WHILE (@FromDate >= @endDate)
BEGIN
PRINT @FromDate
-- Perform your operations here
IF(@FromDate = @BreakDate)
Break;
--Incrementing to next date
SELECT @FromDate = DATEADD(DAY, -1, @FromDate)
END
GO