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

-1 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]
Run Code Online (Sandbox Code Playgroud)

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

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

以上输入的示例结果:

3/15/2015 
3/14/2015 
3/13/2015 
3/11/2015 
3/10/2015 
Run Code Online (Sandbox Code Playgroud)

请帮忙.

Gar*_*thD 5

你不需要循环.你永远不应该用这种心态处理SQL中的问题,它应该是最后的手段.

如果使用日期,那么最简单的解决方案是使用日历表,如果你没有创建日历表,那么你可以使用:

DECLARE @StartDate DATE = '20150315',
        @EndDate DATE = '20150305',
        @BreakDate DATE = '20150310';

SELECT  Date
FROM    Calendar
WHERE   Date <= @StartDate
AND     Date > @EndDate
AND     Date > @BreakDate;
Run Code Online (Sandbox Code Playgroud)

但是,我很欣赏创建日历表并不总是一个选项,但是可以很容易地生成日期列表.来自以下文章:

动态执行此操作的最佳方法是使用常量的交叉连接(在文章中称为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;
Run Code Online (Sandbox Code Playgroud)

编辑

如果您的休息日期可以在开始日期之后,那么您只需要一些额外的逻辑来解决这个问题,因此您的查询将变为:

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
    );
Run Code Online (Sandbox Code Playgroud)

要么

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
    );
Run Code Online (Sandbox Code Playgroud)

  • 我认为改进是可扩展性的,递归CTE并不比while循环好多了 - 我个人不喜欢看到它们在Stackoverflow上以这种方式使用,因为海报可能知道因为它只对几百行表示影响可以忽略不计,但在这种情况下,while循环的性能影响也可以忽略不计,因此这不是一个论据.真正的问题是人们阅读了不知道递归CTE不能扩展的答案,因此将其用于50,000或1,000,000的循环并遇到问题 (2认同)
  • 因此,出于同样的原因,我不主张使用循环,除了处理分层数据时,我不提倡使用递归CTE.使用`spt_values`的解决方案也不会按照当前的形式进行缩放(正如您在答案中指出的那样).因此,虽然我不能代表@gvee回答,但是在您发布答案之后我发布答案的原因是虽然我们的答案之间的性能差异可能很小,但我使用的技术是更好的做法,如测试链接所示在答案中. (2认同)