【问题标题】:Syntax of for-loop in SQL ServerSQL Server中for循环的语法
【发布时间】:2011-08-29 11:13:50
【问题描述】:

TSQL 中for 循环的语法是什么?

【问题讨论】:

  • SQL 与您习惯的语言相比是一种非常不同的语言。它关注的是what,而不是how。你告诉 SQL Server 你想要什么结果,然后让它弄清楚如何产生答案。或者,重新表述一下我刚才所说的 - SQL 中没有 for 循环。
  • WHILE @I < 10; SET @I = @I + 1; BEGIN; ...; END?但是,这应该用于大多数查询处理(但有时需要用于命令式操作)。使用搜索“tsql for loop”可以在 google 上找到许多这样的说明/提示。
  • 避免循环以支持 JOIN 和集合操作。
  • 如果您不是 SQL 专家,则不应考虑使用循环。只有少数情况需要使用循环,而在其余大部分时间,使用循环相当于推动汽车而不是驾驶汽车。学会从数据集的角度思考,而不是遍历记录。 LOoping 是一个专家级功能,不是因为语法难,而是因为你需要确切知道你可以用它造成多大的伤害,然后才能被允许使用它。
  • 有时它可以用来在测试数据库中快速生成测试数据,无论如何你很快就会删除这些数据。在这种情况下,使用它消除了通过类似 C# 编写的单独程序的需要,并且工程并不是特别重要的问题。再说一次,我只是在测试数据方面这么说。

标签: sql sql-server loops tsql syntax


【解决方案1】:

旧线程但仍在出现,我想我会为需要的人提供“FOREACH”解决方案。

DECLARE @myValue nvarchar(45);
DECLARE myCursor CURSOR FOR
SELECT [x] 
FROM (Values ('Value1'),('Value2'),('Value3'),('Value4')) 
as MyTable(x);
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @myValue;
While (@@FETCH_STATUS = 0)
BEGIN
    PRINT @myValue
    FETCH NEXT FROM myCursor INTO @myValue;
END
CLOSE myCursor;     
DEALLOCATE myCursor;

我应该声明一下,递归在 SQL 世界中是不受欢迎的。并且有充分的理由 - 它可能对性能非常不利。不过,对于维护/离线/批量/临时/测试/等操作,我经常使用这种方法。

【讨论】:

    【解决方案2】:

    额外信息

    只是补充一下,因为没有人发布了一个答案,其中包括如何在循环内实际迭代数据集。您可以使用关键字OFFSET FETCH

    用法

    DECLARE @i INT = 0;
    SELECT @count=  Count(*) FROM {TABLE}
    
    WHILE @i <= @count
    BEGIN
           
        SELECT * FROM {TABLE}
        ORDER BY {COLUMN}
        OFFSET @i ROWS   
        FETCH NEXT 1 ROWS ONLY  
    
        SET @i = @i + 1;
    
    END
    

    【讨论】:

    • 使用光标的好选择。
    • 这不是一遍又一遍地执行选择吗?特别是如果它是一个连接并且不能每次都转到特定的行号?
    【解决方案3】:

    尝试一下,学习一下:

    DECLARE @r INT = 5
    DECLARE @i INT = 0
    DECLARE @F varchar(max) = ''
    WHILE @i < @r
    BEGIN
    
        DECLARE @j INT = 0
        DECLARE @o varchar(max) = ''
        WHILE @j < @r - @i - 1
        BEGIN
            SET @o = @o + ' '
            SET @j += 1
        END
    
        DECLARE @k INT = 0
        WHILE @k < @i + 1
        BEGIN
            SET @o = @o + ' *'  -- '*'
            SET @k += 1
        END
        SET @i += 1
        SET @F = @F + @o + CHAR(13)
    END
    PRINT @F
    

    日期:

    DECLARE @d DATE = '2019-11-01'
    WHILE @d < GETDATE()
    BEGIN
        PRINT @d
        SET @d = DATEADD(DAY,1,@d)
    END
    PRINT 'n'
    PRINT @d
    

    【讨论】:

      【解决方案4】:

      T-SQL 中的 While 循环示例,列出当前月份的开始到结束日期。

      DECLARE @Today DATE= GETDATE() ,
      @StartOfMonth DATE ,
      @EndOfMonth DATE;
      
      DECLARE @DateList TABLE ( DateLabel VARCHAR(10) );
      SET @EndOfMonth = EOMONTH(GETDATE());
      SET @StartOfMonth = DATEFROMPARTS(YEAR(@Today), MONTH(@Today), 1);
      
      WHILE @StartOfMonth <= @EndOfMonth
      BEGIN
          INSERT  INTO @DateList
          VALUES  ( @StartOfMonth );
          SET @StartOfMonth = DATEADD(DAY, 1, @StartOfMonth);
      END;
      
      SELECT  DateLabel
      FROM    @DateList;  
      

      【讨论】:

        【解决方案5】:

        SQL Server 尚未正式支持 For 循环。已经有answer 关于实现FOR Loop 的不同方式。我正在详细解答在 SQL Server 中实现不同类型循环的方法。

        FOR 循环

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

        如果您知道,无论如何您都需要完成循环的第一次迭代,那么您可以尝试 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;
        

        Reference

        【讨论】:

        • 这似乎已在此处复制-粘贴-重新排序:stackoverflow.com/a/46363319/8239061
        • @SecretAgentMan:两个答案都在回答不同的问题。两个答案中都给出了额外的数据。
        • 问题并没有太大的不同。我认为它们是重复的。
        【解决方案6】:

        T-SQL 没有FOR 循环,它有一个WHILE 循环
        WHILE (Transact-SQL)

        WHILE Boolean_expression
        BEGIN
        
        END
        

        【讨论】:

        • JOIN(和集合操作)应该优先于 SQL 中的循环结构。
        • 强调没有限制(特别是对于那些刚接触 SQL 的人),正如 Damien 所说:“与你习惯的语言相比,SQL 是一种非常不同的语言。它专注于关于什么,而不是如何。你告诉 SQL Server 你想要什么结果,然后让它弄清楚如何产生答案。"
        • 有趣的是,这里的 MS 文档是错误的,真的。 WHILE 不采用布尔表达式 - 它采用谓词 - 除了能够评估为 TRUE 或 FALSE 之外,还可能是 UNKNOWN。
        【解决方案7】:

        这个怎么样:

        BEGIN
           Do Something
        END
        GO 10
        

        ...当然,如果需要计数,您可以在其中放置一个增量计数器。

        【讨论】:

        • 'GO 10'? SQL Server 2008 不喜欢它。
        【解决方案8】:

        没有for循环,只有while循环:

        DECLARE @i int = 0
        
        WHILE @i < 20
        BEGIN
            SET @i = @i + 1
            /* do some work */
        END
        

        【讨论】:

        • 请注意,如果您打算在循环中使用索引,您可能希望增加最后一项而不是第一项,具体取决于您的用例。
        • 另请注意,普通 SQL 不支持局部变量的默认值。因此,在 for 循环之前您需要单独的 SET @i = 0
        • @Nux:0 是在声明期间明确设置的
        • 是的,但这不适用于较旧的 SQL Server(至少在 2005 年不适用)。
        • 另外,应该注意的是,通常工作是在整数递增之前完成的。 SQL 中的许多 for 循环实际上在其工作中使用该整数(从行到行或结果迭代以生成临时表)并且如果增量发生在循环开始而不是结束时可能会被丢弃。跨度>
        【解决方案9】:

        简单的答案是NO !!

        SQL中没有FOR,但是可以使用WHILE或者GOTO来实现 FOR 的工作方式。

        同时:

        DECLARE @a INT = 10
        
        WHILE @a <= 20
        BEGIN
            PRINT @a
            SET @a = @a + 1
        END
        

        转到:

        DECLARE @a INT = 10
        a:
        PRINT @a
        SET @a = @a + 1
        IF @a < = 20
        BEGIN
            GOTO a
        END
        

        我总是更喜欢 WHILE 而不是 GOTO 声明。

        【讨论】:

        • 我喜欢你提到的两种选择,而不是像大多数答案一样只有 1 个
        【解决方案10】:

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

        【讨论】:

        • 欢迎来到 Stack Overflow!您是否会考虑添加一些叙述来解释为什么此代码有效,以及是什么使它成为问题的答案?这对提出问题的人以及其他任何出现的人都非常有帮助。
        • 这是不言自明的。
        • 这怎么不是不言自明的?我有同样的问题,我马上明白了答案。
        • 除了命名约定之外,这个答案与@TcKs 有何不同?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-18
        • 2018-02-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多