Sql server 我需要一个sql查询循环,日期递减一天,直到中断日期
我需要一个sql查询循环,日期按天递减Sql server 我需要一个sql查询循环,日期递减一天,直到中断日期,sql-server,sql-server-2008,Sql Server,Sql Server 2008,我需要一个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] 循环中的当前日期应从开始日期到结束日期按天递减打印 如果达到中断日期,则循环应自行停止[在循环内] 上述输入
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
请提供帮助。此解决方案限制为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
您可以通过WHILE循环来完成此操作。但是在循环之前,考虑一下.< /P>
这将提供预期的准确输出
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
家庭作业
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
您不需要循环。您永远不应该以这种心态处理SQL中的问题,这应该是最后的手段 如果使用日期,则最简单的解决方案是使用,如果您没有创建日期,则可以使用:
DECLARE @StartDate DATE = '20150315',
@EndDate DATE = '20150305',
@BreakDate DATE = '20150310';
SELECT Date
FROM Calendar
WHERE Date <= @StartDate
AND Date > @EndDate
AND Date > @BreakDate;
然而,我知道创建日历表并不总是一个选项,但是动态生成日期列表非常容易。从以下条款:
动态执行此操作的最佳方法是使用文章中称为堆叠CTE的常量的交叉联接。这只是从一个包含10行的表值构造函数开始,将其交叉连接到自身以获得100行,然后再次获得100x100=10000行,依此类推:
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
);
或
您的字面意思是像使用print语句一样打印,而不是作为查询结果返回吗?因为打印它确实需要一个循环,但是作为查询结果返回它需要一个递归CTE。使用日历表。答案非常简单:从dbo.calendar中选择_日期,其中…不确定为什么会出现最差的答案。循环是个坏主意。选择@GarethD的答案。那会让我睡得更好你犯了和我一开始犯的同样的错误。试试“20150320”上的breakdate,它将排除所有可能发布的最佳方法@t-clausen.dk easy fix:如果@BreakDate的改进是可伸缩性的,那么递归CTE并不比while循环好多少——我个人不喜欢在Stackoverflow上以这种方式使用它们,因为海报可能知道,因为只有几百行,性能影响可以忽略不计,但是在这种情况下,while循环对性能的影响也可以忽略不计,所以这不是一个论点。真正的问题是阅读答案的人不知道递归CTE不可伸缩,因此将其用于50000或1000000的循环并遇到问题。因此,出于同样的原因,我不提倡使用循环,我不提倡使用递归CTE,除非处理分层数据。正如您在回答中指出的,使用spt_值的解决方案也不能按当前形式进行缩放。因此,虽然我不能代表@gvee回答问题,但我在您发布答案后发布答案的原因是,尽管我们的答案之间的性能差异可能很小,但我使用的技巧更好,如答案中链接的测试所示。
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
);