在SQL Server 2008中执行while循环


120

do while在SQL Server 2008中是否有实现循环的方法?


5
拉胡尔给出的答案是正确的,但是您到底想达到什么目的?与基于集合的解决方案相比,循环是昂贵的。也许有可能完全避免循环。
Lieven Keersmaekers,2010年

尽可能不要使用循环,我估计有95%或更多的时间可以避免使用循环。循环和游标是性能的杀手,绝不应该由经验丰富的DBA进行至少五年的性能调整的人来编写。
HLGEM 2014年

1
呃。只要您不遍历表中的每一行,HLGEM,循环和游标实际上都非常整洁。如果您具有类别或站点列表或相对较高级别的列表,则循环很可能是运行查询的最有效方法。
杰夫·格里斯瓦尔德

Answers:


190

我不确定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/

  1. WHILE循环示例

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

    结果集:

    1
    2
    3
    4
    5
  2. 带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
  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

但是,请尝试避免在数据库级别出现循环参考


17
这里给出了相同的示例,您是该网站的作者吗?blog.sqlauthority.com/2007/10/24/...
ANAR哈利洛夫

1
他不是,但是为什么重要呢?给出了正确的答案。链接到另一个网站是很痛苦的,将答案复制并粘贴到此处很有帮助。
杰夫·格里斯瓦尔德

61

如果您对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很少。


重复/直到任何人(在T-SQL中不起作用)?

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

...以及GOTOT-SQL中的基础解决方案:

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


6
+1:绝对比接受的答案要好。
路易·科特曼

我更喜欢WHILE(1 = 1)方法,因为它在功能上符合目的,而无需使用可怕的GOTO。
kad81

两种方法均有效。我喜欢使用GOTO的伪循环,它非常聪明。
杰夫·格里斯瓦尔德

18

我似乎记得不止一次阅读本文,而且答案仅与我所需要的接近

通常,当我认为我需要使用DO WHILET-SQL时,是因为我要遍历游标,而我主要是在寻求最佳清晰度(相对于最佳速度)。在T-SQL中,似乎适合WHILE TRUE/ IF BREAK

如果真是这样的话,那么此片段可能会节省您一些时间。否则,欢迎回来,我。现在我可以确定我已经来过这里一次以上。:)

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 2014年

10
@greektreat:谢谢你的不赞成:),但我很困惑!如果“游标永远不是一个好选择”,那么它一定永远是一个好选择,那么为什么要投反对票呢?但是,严重的是,游标显然具有许多相当实用的用途:针对私有表,针对清晰/简洁>性能的小型操作,针对维护任务,无法进行确定性操作的维护,对于某些操作无论如何都必须作为原子事务进行,等等。在最近的情况下,我正在摄取一个传入表变量,该变量对我的存储过程是私有的。绝对陈词滥调不是一个好主意!
香农2014年

5
@greektreat:总而言之,有时迭代数据是唯一的选择。我想您仍然可以认为,在这种情况下,这不是一个好选择,但这并不意味着这种代码是不必要的,需要降低投票权。
香农2014年

1
我认为互联网上有一群狂热的人,他们非常讨厌其他人在SQL中使用循环和游标。在这个网站上,如果您甚至提到在30秒后使用SQL循环,您的收件箱就会被无知的人淹没,告诉您在任何情况下都不要使用它们……
Geoff Griswald

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”仍然适用。
杰夫·格里斯瓦尔德

1

SQL Server正式支持Only While Loop。已经有答案了 DO循环的。我正在详细说明在SQL Server中实现不同类型的循环的方法的答案。

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

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';

参考


这看起来像是stackoverflow.com/a/46362450/8239061的复制粘贴重新排序。
SecretAgentMan

@SecretAgentMan:两个答案都回答了不同的问题。两个答案中都给出了其他数据。
Somnath Muluk,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.