我需要一个sql查询循环,日期减少一天,直到休息日期

时间:2015-03-05 12:47:46

标签: 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]

当前日期(循环中)应从开始日期到结束日期打印一天减量

如果达到中断日期,那么循环应该自行停止[内循环]

输入上面的示例结果:

3/15/2015 
3/14/2015 
3/13/2015 
3/11/2015 
3/10/2015 

请帮助。

4 个答案:

答案 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