为什么在此SQL While循环中返回相同的值?

2022-03-08 00:00:00 sql tsql sql-server ssms

我正在使用Microsoft SQL Server,并尝试将一些数据插入到临时表中。然后,我希望使用WHILE循环遍历临时表中的每一行。我不想使用光标。

请参见以下查询:

-- Create Table

DROP TABLE IF EXISTS #TMP_ABC

CREATE TABLE #TMP_ABC

(
  [ABC] [varchar](3) NULL,
)
 
-- Insert Values
INSERT INTO [#TMP_ABC] VALUES ('AAA')
INSERT INTO [#TMP_ABC] VALUES ('BBB')
INSERT INTO [#TMP_ABC] VALUES ('CCC')
INSERT INTO [#TMP_ABC] VALUES ('DDD')
INSERT INTO [#TMP_ABC] VALUES ('EEE')
INSERT INTO [#TMP_ABC] VALUES ('FFF')
 
-- Display values

DECLARE @count INT
DECLARE @row INT
SET @row = 1;

DECLARE @ABC varchar(3)

SET @count = (SELECT COUNT(ABC) FROM #TMP_ABC)

WHILE (@row <= @count) BEGIN
    SELECT @ABC = ABC FROM #TMP_ABC
    PRINT @ABC
    SET @row += 1
END

以下是查询返回的内容:

(1 row affected)
FFF
FFF
FFF
FFF
FFF
FFF

我希望返回以下内容:

(1 row affected)
AAA
BBB
CCC
DDD
EEE
FFF

请有人"好心"向我展示一下我前进道路上的错误,以及如何做到这一点?


解决方案

发生此问题是因为SQL Server没有将@row与表中的行相关联(这种关联对您来说很明显,但SQL Server不是人)。

当您循环数字1 -> @count时,它会反复运行相同的SELECT @ABC = ABC FROM #TMP_ABC。没有WHERE子句和TOP,因此SQL Server每次都只是读取整个表,并将变量设置为等于它读取的最后ABC值。

相反,您应该使用游标(如果您需要循环;通常不需要,根据@Larnu's comment)。您在某处读到了一些错误信息,认为游标是错误的,而While循环不是游标,但这两者都是错误的。

  • Bad Habits to Kick : Thinking a WHILE loop isn't a CURSOR
  • What impact can different cursor options have?
  • Follow-up on cursor options
  • Overlooked T-SQL Gems(请参阅为什么对游标使用局部变量比您可能使用的常规类型更好)

如果您确实出于某种原因需要循环,则重写如下:

CREATE TABLE #TMP_ABC(ABC varchar(3));

INSERT INTO #TMP_ABC(ABC) VALUES 
  ('AAA'),('BBB'),('CCC'),('DDD'),('EEE'),('FFF');
  
DECLARE @ABC varchar(3), @c cursor;
    
SET @c = cursor LOCAL FAST_FORWARD
    FOR SELECT ABC FROM #TMP_ABC;

OPEN @c;
FETCH NEXT FROM @c INTO @ABC;

WHILE @@FETCH_STATUS = 0
BEGIN
  PRINT @ABC;
  FETCH NEXT FROM @c INTO @ABC;
END

输出:

AAA
BBB
CCC
DDD
EEE
FFF
  • 示例db<>fiddle

但我不确定这比SELECT ABC FROM #TMP_ABC;完成了什么。

相关文章