Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 我需要一个sql查询循环,日期递减一天,直到中断日期_Sql Server_Sql Server 2008 - Fatal编程技术网

Sql server 我需要一个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] 循环中的当前日期应从开始日期到结束日期按天递减打印 如果达到中断日期,则循环应自行停止[在循环内] 上述输入

我需要一个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 

请提供帮助。

此解决方案限制为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
    );