在需要计数器时避免 SQL 中的 while 循环

Posted

技术标签:

【中文标题】在需要计数器时避免 SQL 中的 while 循环【英文标题】:Avoiding while loops in SQL when a counter is required 【发布时间】:2014-07-22 20:28:09 【问题描述】:

我觉得这是一个常见问题,但似乎我在 SO 或其他网站上找到的答案似乎都没有解决带有计数器的 while 循环问题。

假设我正在尝试用 SQL 编写一个存储过程,该过程将通过在当月剩余时间的每一天插入一行来填充用户的时间表。如果 @endMonth 变量包含该月的最后一天,那么我知道我可以轻松编写一个 while 循环并按照以下方式执行一些操作:

WHILE @date <= @endMonth
BEGIN
    //Do some action with the date, like an insert
    SET @date = DATEADD(d, 1, @date) //increment the date by one day
END

但是,查看 here 和其他网站上的答案让我相信,如果可能的话,最好避免使用 while 循环。

所以我的问题是:有没有一种方法可以在不使用WHILE 结构的情况下在SQL 中实现带有计数器的循环?我将使用什么技术来转换类似于我发布的循环?或者像这样的东西,我是否必须硬着头皮只使用一个while循环?

顺便说一句,以下一些问题很接近,但似乎都没有完全解决需要计数器作为循环条件的问题。大多数答案似乎都谴责使用WHILE 循环,但我似乎无法找到通用解决方案作为替代方案。 sql while loop with date counter SQL Server 2008 Insert with WHILE LOOP(这个很接近,但不幸的是对我来说它只适用于自动增量列)

【问题讨论】:

在那种情况下,如果缺少的代码是为每一天插入一条记录,那么您可以通过加入发现缺少日期的 CTE 来做到这一点。摆脱 while 循环的一般情况,值得注意的是我应该认为的例外情况......顺便说一下,这里有大量 CTE 示例来生成一系列日期,通常用于计算工作日等。 这是我一直以来的疑问。当我无法在 SQL 中绕过它时,我个人仍然使用 while 循环,即使我被告知不要这样做。没有人提供过它不好的具体原因。 这很糟糕,因为它需要更长的时间并且使用更多的资源。 SQL 是一种基于集合的语言。 【参考方案1】:

我看到了很多填充数据的例子。

首先您在 cte 中创建从开始日期到结束日期的日期,然后您可以将其插入到表格中。

其中一个是 cte:

DECLARE @StartDate DateTime = '2014-06-01'
DECLARE @EndDate DateTime = '2014-06-29'



;WITH populateDates (dates) AS (

    SELECT @StartDate as dates
    UNION ALL
    SELECT DATEADD(d, 1, dates)
    FROM populateDates
    WHERE DATEADD(d, 1, dates)<=@EndDate

)
SELECT *
INTO dbo.SomeTable
FROM populateDates

你应该尝试在互联网上寻找how to populate date in sql table

【讨论】:

虽然我希望为带有计数器的循环提供更通用的解决方案,但这似乎适用于日期计数器。尽管我不得不承认,我在 CTE 明显的速度优势和 while 循环的可读性之间左右为难。无论如何,谢谢。【参考方案2】:

一般情况下,您可以在不使用游标的情况下通过在同一个选择中分配值和递增变量来递增值,如下所示:

DECLARE @i INT = 0

DECLARE @table TABLE
    (
      ID INT ,
      testfield VARCHAR(5)
    )

INSERT  INTO @table
        ( testfield )
VALUES  ( 'abcd'),
        ( 'efgh' ),
        ( 'ijkl' ),
        ( 'mnop' )


UPDATE  @table
SET     @I = ID = @i + 1

SELECT  *
FROM    @table

【讨论】:

这是一个有趣的技巧,但我不确定我是否理解如何使用它来替换 while 循环。

以上是关于在需要计数器时避免 SQL 中的 while 循环的主要内容,如果未能解决你的问题,请参考以下文章

带有日期计数器的sql while循环

Thread.sleep() 在 while 循环中

SQL——While循环

SQL——While循环

python之while与for循环,break与continue

为啥'continue'语句忽略'while'循环中的循环计数器增量,而不是'for'循环?