【问题标题】:Nested while statements only running inner while SQL嵌套的 while 语句仅在内部运行 SQL
【发布时间】:2021-12-27 00:00:39
【问题描述】:

我正在尝试创建一个包含以下行的表:

Date Value
01/01/2021 1.0
01/02/2021 0.5
01/02/2021 0.5
01/03/2021 0.33
01/03/2021 0.33
01/03/2021 0.33
01/04/2021 0.25
01/04/2021 0.25
01/04/2021 0.25
01/04/2021 0.25

我在下面的尝试似乎只运行内部语句,外部语句是多余的,但是当我自己运行外部语句时,它会返回所有结束日期组合。

我确定我遗漏了一些非常简单的东西。

提前致谢。

SET DATEFORMAT dmy;

SET @start   = '01/09/2021'
SET @end     = '01/09/2025'
SET @counter = 1
    
WHILE (@end> @start)
BEGIN
    
    WHILE (@counter < DATEDIFF(m,@start,@end))
    BEGIN

        INSERT INTO #timerevert (mon,frac)
        VALUES( @end, 1 / (datediff(m,@start,@end)*1.0) )
    
    SET @counter = @counter + 1
    
    END

    SET @end = dateadd(mm,-1,@end)

END

【问题讨论】:

  • Protip:你不需要WHILE 循环,也不需要#temporary 表。相反,尝试考虑如何使用集合理论运算来描述数据(提示:您的 Value 显然是 Date 的函数)。
  • 它使用 SET DATEFORMAT dmy;一开始,抱歉,这不是创建表和声明变量的完整查询。
  • 这是一个简单的基于集合的查询,如果您手头有 数字/计数表,则非常容易。
  • @Stu 我原以为自引用 CTE 会更好地生成行ex nihilo
  • 确认一下,2021-01-01 需要 1 行,2021-01-02 需要 2 行,2021-01-03 需要 3 行,2021-01-04 需要 4 行,2021-12-31 需要 365 行?这将是 2021 年总共 66,795 行 - 但您想一直到 2025 年...您确定这就是您想要的吗?我看到您的 @start 变量是 2021-09-01 而不是 2021-01-01,所以我不确定您真正想要什么...

标签: sql loops while-loop


【解决方案1】:

(当我声称您不需要 WHILE 循环时,我的 cmets 是错误的。虽然 从技术上讲很可能生成行 ex nihilo 使用CTE 或类似的,不幸的是,T-SQL 并没有使它成为一种“更好”的方法:例如,CTE 有一个递归限制,这种类型的查询会很快达到)。

我下面的方法将问题分为两部分:

  1. 第一部分生成一个简单的日期范围表变量,其中包括一个 n int 列,即 number-of-days-since-2021-01-01 - 它还额外提供作为您想要多少重复行的值(因为您希望同一行重复n 次,其中nnumber-of-days-since-2021-01-01。李>
  2. 那么简单的日期列表是CROSS APPLY-d 到它自己,然后为number-of-days-since-2021-01-01生成额外的行。

警告:对于日期范围 2021-01-012025-09-01,这会生成 1,452,660 行,并在我使用了 6 年的 LAN 开发服务器上运行了 5 秒(2013 年的一些低端至强芯片)。


DECLARE @dates TABLE (
    n int  NOT NULL IDENTITY(1,1) PRIMARY KEY,
    d date NOT NULL 
);

-- Part 1:
BEGIN
    DECLARE @start date = '2021-01-01';
    DECLARE @end   date = '2025-09-01';
    DECLARE @i     date = @start;
    
    WHILE @i < @end
    BEGIN
        INSERT INTO @dates ( d ) VALUES ( @i );
        SET @i = DATEADD( day, 1, @i );
    END;
    
END;

-- Part 2:
SELECT
    dt.n,
    dt.d AS [Date],
    dtn.dateSubRowNumber,
    ( 1.0 / dt.n ) AS [Value]
FROM
    @dates AS dt
    CROSS APPLY
    (
        SELECT
            TOP ( dt.n )
            dti.n AS dateSubRowNumber,
            dti.d
        FROM
            @dates AS dti
        ORDER BY
            dti.n
    ) AS dtn;

注释掉外部的 dt.n 和 dtn.dateSubRowNumber` 列以获得与示例预期输出完全相同的输出。

输出:

【讨论】:

    猜你喜欢
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 2022-01-09
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    • 2018-07-28
    相关资源
    最近更新 更多