为什么在这个 SQL While 循环中相同的值是 return?
Why is the same value being return in this SQL While Loop?
我正在使用 Microsoft SQL 服务器,并试图将一些数据插入临时 table。然后我想使用 while 循环遍历临时 table 中的每一行。我不想使用游标。
请看下面的查询:
-- 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
请有人 'kindly' 告诉我我的方法中的错误,以及如何实现这个?
出现此问题是因为 SQL 服务器未将 @row
与 table 中的一行相关联(相关性对您来说很明显,但 SQL 服务器不是不是人类)。
当您遍历数字 1 -> @count
时,它会一遍又一遍地 运行 相同的 SELECT @ABC = ABC FROM #TMP_ABC
。没有 WHERE
子句,也没有 TOP
,所以 SQL 服务器每次只是读取整个 table,并将变量设置为等于最后一个 ABC
值它读到。
相反,您应该使用游标(如果您需要循环;根据 ,通常不需要)。您已经在某处读到一些错误信息,说游标不好,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
但我不确定 SELECT ABC FROM #TMP_ABC;
完成了什么。
使用 ROW_NUMBER() 函数并通过循环中 WHERE 子句中的变量传递值。
--Create another Temp table
CREATE table #Tem_abc (r int , abc varchar(3));
--Add Row number
insert into #Tem_abc
select ROW_NUMBER() over( order by ABC) as r,*
from #TMP_ABC;
--Use the loop
DECLARE @count INT;
DECLARE @row INT;
SET @row = 1;
DECLARE @ABC varchar(3);
SET @count = (SELECT COUNT(ABC) FROM #TMP_ABC);
--SET @count = (SELECT max(r) FROM #Tem_abc);
WHILE (@row <= @count) BEGIN
SELECT @ABC = ABC FROM #Tem_abc where @row = r;
PRINT @ABC;
SET @row += 1;
END
我正在使用 Microsoft SQL 服务器,并试图将一些数据插入临时 table。然后我想使用 while 循环遍历临时 table 中的每一行。我不想使用游标。
请看下面的查询:
-- 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
请有人 'kindly' 告诉我我的方法中的错误,以及如何实现这个?
出现此问题是因为 SQL 服务器未将 @row
与 table 中的一行相关联(相关性对您来说很明显,但 SQL 服务器不是不是人类)。
当您遍历数字 1 -> @count
时,它会一遍又一遍地 运行 相同的 SELECT @ABC = ABC FROM #TMP_ABC
。没有 WHERE
子句,也没有 TOP
,所以 SQL 服务器每次只是读取整个 table,并将变量设置为等于最后一个 ABC
值它读到。
相反,您应该使用游标(如果您需要循环;根据
- 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
但我不确定 SELECT ABC FROM #TMP_ABC;
完成了什么。
使用 ROW_NUMBER() 函数并通过循环中 WHERE 子句中的变量传递值。
--Create another Temp table
CREATE table #Tem_abc (r int , abc varchar(3));
--Add Row number
insert into #Tem_abc
select ROW_NUMBER() over( order by ABC) as r,*
from #TMP_ABC;
--Use the loop
DECLARE @count INT;
DECLARE @row INT;
SET @row = 1;
DECLARE @ABC varchar(3);
SET @count = (SELECT COUNT(ABC) FROM #TMP_ABC);
--SET @count = (SELECT max(r) FROM #Tem_abc);
WHILE (@row <= @count) BEGIN
SELECT @ABC = ABC FROM #Tem_abc where @row = r;
PRINT @ABC;
SET @row += 1;
END