在 SQL Server 2008 中执行 while 循环

Posted

技术标签:

【中文标题】在 SQL Server 2008 中执行 while 循环【英文标题】:Do while loop in SQL Server 2008 【发布时间】:2011-05-28 02:48:12 【问题描述】:

SQL server 2008 有没有实现do while循环的方法?

【问题讨论】:

Rahul 给出的答案是正确的,但您到底想达到什么目的?与基于集合的解决方案相比,循环是昂贵的。也许可以完全避免循环。 尽可能不要使用循环,我估计 95% 或更多的时间可以避免它们。循环和游标是性能杀手,任何不是具有至少五年性能调优经验的 DBA 的人都不应编写。 呃。 HLGEM 中略显戏剧性,只要您不循环遍历表中的每一行,循环和游标实际上就非常整洁。如果您有一个类别或网站列表或相对较高级别的内容,那么循环可能是运行查询的最有效方式。 【参考方案1】:

我不确定 MS SQL Server 2008 中的 DO-WHILE,但您可以更改 WHILE 循环逻辑,以便像 DO-WHILE 循环一样使用。

示例取自这里:http://blog.sqlauthority.com/2007/10/24/sql-server-simple-example-of-while-loop-with-continue-and-break-keywords/

    WHILE 循环示例

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
    END
    GO
    

    结果集:

    1
    2
    3
    4
    5
    

    带有 BREAK 关键字的 WHILE 循环示例

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
        IF @intFlag = 4
            BREAK;
    END
    GO
    

    结果集:

    1
    2
    3
    

    使用 CONTINUE 和 BREAK 关键字的 WHILE 循环示例

    DECLARE @intFlag INT
    SET @intFlag = 1
    WHILE (@intFlag <=5)
    BEGIN
        PRINT @intFlag
        SET @intFlag = @intFlag + 1
        CONTINUE;
        IF @intFlag = 4 -- This will never executed
            BREAK;
    END
    GO
    

    结果集:

    1
    2
    3
    4
    5
    

但请尝试在数据库级别避免循环。 Reference.

【讨论】:

这里给出相同的例子,你是这个网站的作者吗? blog.sqlauthority.com/2007/10/24/… 他不是,但这有什么关系呢?给出了正确答案。链接到另一个网站很痛苦,在这里复制和粘贴答案很有帮助。【参考方案2】:

如果你对GOTO关键字不是很反感,可以用它来模拟T-SQL中的DO/WHILE。考虑以下用伪代码编写的相当荒谬的示例:

SET I=1
DO
 PRINT I
 SET I=I+1
WHILE I<=10

这是使用 goto 的等效 T-SQL 代码:

DECLARE @I INT=1;
START:                -- DO
  PRINT @I;
  SET @I+=1;
IF @I<=10 GOTO START; -- WHILE @I<=10

注意GOTO 启用的解决方案和原始DO / WHILE 伪代码之间的一对一映射。使用WHILE 循环的类似实现如下所示:

DECLARE @I INT=1;
WHILE (1=1)              -- DO
 BEGIN
  PRINT @I;
  SET @I+=1;
  IF NOT (@I<=10) BREAK; -- WHILE @I<=10
 END

现在,您当然可以将此特定示例重写为简单的WHILE 循环,因为这不是DO / WHILE 构造的理想候选者。重点在于示例的简洁性而不是适用性,因为需要DO / WHILE 的合法案例很少见。


REPEAT / UNTIL,任何人(不在 T-SQL 中工作)?

SET I=1
REPEAT
  PRINT I
  SET I=I+1
UNTIL I>10

...以及 T-SQL 中基于 GOTO 的解决方案:

DECLARE @I INT=1;
START:                    -- REPEAT
  PRINT @I;
  SET @I+=1;
IF NOT(@I>10) GOTO START; -- UNTIL @I>10

通过GOTO 的创造性使用和NOT 关键字的逻辑反转,原始伪代码与基于GOTO 的解决方案之间存在非常密切的关系。使用WHILE 循环的类似解决方案如下所示:

DECLARE @I INT=1;
WHILE (1=1)       -- REPEAT
 BEGIN
  PRINT @I;
  SET @I+=1;
  IF @I>10 BREAK; -- UNTIL @I>10
 END

可以说,对于REPEAT / UNTIL 的情况,基于WHILE 的解决方案更简单,因为if 条件没有反转。另一方面,它也更冗长。

如果不是因为所有对使用 GOTO 的蔑视,这些甚至可能是一些惯用的解决方案,因为在 T-SQL 代码中为了清晰度。

您可以自行决定使用它们,当您的开发人员发现您使用备受诟病的 GOTO 时,尽量不要让他们感到愤怒。

【讨论】:

+1:肯定比接受的答案更好地回答问题。 我更喜欢 WHILE (1 = 1) 方法,因为它在功能上符合目的而无需使用可怕的 GOTO。 两种方法都有效。我喜欢使用 GOTO 的伪循环,它很聪明。【参考方案3】:

我似乎记得不止一次阅读这篇文章,答案只是接近我需要的。

通常当我认为我需要在 T-SQL 中使用 DO WHILE 时,这是因为我正在迭代一个游标,并且我主要在寻找最佳清晰度(相对于最佳速度)。在似乎适合 WHILE TRUE / IF BREAK 的 T-SQL 中。

如果这就是将您带到这里的场景,那么这个 sn-p 可能会为您节省一点时间。否则,欢迎回来,我。现在我可以确定我不止一次来过这里。 :)

DECLARE Id INT, @Title VARCHAR(50)
DECLARE Iterator CURSOR FORWARD_ONLY FOR
SELECT Id, Title FROM dbo.SourceTable
OPEN Iterator
WHILE 1=1 BEGIN
    FETCH NEXT FROM @InputTable INTO @Id, @Title
    IF @@FETCH_STATUS < 0 BREAK
    PRINT 'Do something with ' + @Title
END
CLOSE Iterator
DEALLOCATE Iterator

不幸的是,T-SQL 似乎没有提供比无限循环更简洁的方法来单独定义循环操作。

【讨论】:

使用游标从来都不是一个好的选择,因为它需要更多实际需要的资源。 @greektreat:感谢您的反对:),但我很困惑!如果“游标永远不是一个好选择”,那么它必须始终是一个好选择,那么为什么要投反对票呢?不过,说真的,游标显然有许多非常实际的用途:针对私有表,用于清晰度/简洁性 > 性能的小型操作,用于维护任务,其中确定性操作不可用,某些操作无论如何都必须作为原子事务发生,等等。在我最近的案例中,我正在摄取一个传入的表变量,它是我的存储过程私有的。绝对的陈词滥调绝不是一个好主意! @greektreat:总而言之,有时迭代数据是唯一的选择。我想你仍然可以争辩在这种情况下它不是一个好的选择,但这并不意味着这种代码是不必要的并且需要被否决。 我认为互联网上有一群***的人,他们对其他人在 SQL 中使用循环和游标感到非常非常愤怒。在这个网站上,如果您在大约 30 秒后提到在 SQL 中使用循环,那么您的收件箱就会被无知的人淹没,告诉您在任何情况下都不要使用它们......【参考方案4】:

如果您希望代码更具可读性,也可以使用退出变量:

DECLARE @Flag int = 0
DECLARE @Done bit = 0

WHILE @Done = 0 BEGIN
    SET @Flag = @Flag + 1
    PRINT @Flag
    IF @Flag >= 5 SET @Done = 1
END

当您有一个更复杂的循环并试图跟踪逻辑时,这可能会更相关。如前所述,循环很昂贵,因此请尽可能尝试使用其他方法。

【讨论】:

我的意思是......我们生活在这样一个时代,我们的数据库服务器在任何给定时刻都有 10 到 20 个 CPU 内核空闲,并且我们的存储控制器的可用带宽以千兆位为单位,所以我不确定“LOOP = BAD”这种传统的“智慧”是否仍然适用。【参考方案5】:

只有 While 循环被 SQL 服务器官方支持。已经有 answer 用于 DO while 循环。我正在详细解答在 SQL Server 中实现不同类型循环的方法。

如果您知道,无论如何您都需要完成循环的第一次迭代,那么您可以尝试 DO..WHILEREPEAT..UNTIL 版本的 SQL Server。

DO..WHILE 循环

DECLARE @X INT=1;

WAY:  --> Here the  DO statement

  PRINT @X;

  SET @X += 1;

IF @X<=10 GOTO WAY;

REPEAT..UNTIL 循环

DECLARE @X INT = 1;

WAY:  -- Here the REPEAT statement

  PRINT @X;

  SET @X += 1;

IFNOT(@X > 10) GOTO WAY;

FOR 循环

DECLARE @cnt INT = 0;

WHILE @cnt < 10
BEGIN
   PRINT 'Inside FOR LOOP';
   SET @cnt = @cnt + 1;
END;

PRINT 'Done FOR LOOP';

Reference

【讨论】:

这似乎是来自***.com/a/46362450/8239061 的复制粘贴重新排序。 @SecretAgentMan:两个答案都在回答不同的问题。两个答案中都给出了额外的数据。

以上是关于在 SQL Server 2008 中执行 while 循环的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 2008 上执行整个 .sql 文件

如何在 SQL Server 2005/2008 中清除查询执行统计信息

在 SQL Server 2008 中执行 while 循环

在 SQL Server 2008 中执行视图时出现“超时已过期”错误

如何查看sql server 2008的SQL语句执行错误日志

在 SQL Server 2008 上执行 SQL Server 7 DTS