如何在 SQL Server 的 While 循环中设置变量
Posted
技术标签:
【中文标题】如何在 SQL Server 的 While 循环中设置变量【英文标题】:How to set variables in While Loop in Sql Server 【发布时间】:2016-09-13 11:26:35 【问题描述】:我正在尝试在 SQL SERVER 中使用 while 循环而不是 CURSOR。我正在尝试在 while 中选择 TOP 1 并将它们设置为如下所示的变量。它不允许我在 while 循环中设置变量。我做错了什么?
WHILE (
SELECT TOP 1 @WAOR_CODE = WAOR_.WAOR_CODE
, @WAOD_INVENTORYITEMID = WAOD_.WAOD_INVENTORYITEMID
FROM #wmsorder
)
BEGIN
SELECT @WAOR_CODE
, @WAOD_INVENTORYITEMID
DELETE TOP (1) #wmsorder
END
【问题讨论】:
【参考方案1】:另一种选择:
WHILE EXISTS(select 1 FROM #wmsorder)
BEGIN
DELETE TOP (1)
FROM #wmsorder
END
但是,从一个表中一个一个地删除所有记录可能是一个性能地狱。您可能要考虑改用TRUNCATE TABLE
:
TRUNCATE TABLE #wmsorder
另外,请注意,每次删除都会写入数据库日志,而 truncate table 根本不会写入日志。
使用包含 100,000 行的临时表进行测试,一一删除行花了我 9 秒,而 truncate table 立即完成:
-- create and populate sample table
SELECT TOP 100000 IDENTITY(int,1,1) AS Number
INTO #wmsorder
FROM sys.objects s1
CROSS JOIN sys.objects s2
-- delete rows one by one
WHILE EXISTS(select 1 FROM #wmsorder)
BEGIN
DELETE TOP (1)
FROM #wmsorder
END
-- clean up
DROP TABLE #wmsorder
-- create and populate sample table
SELECT TOP 100000 IDENTITY(int,1,1) AS Number
INTO #wmsorder
FROM sys.objects s1
CROSS JOIN sys.objects s2
-- truncate the table
TRUNCATE TABLE #wmsorder
-- clean up
DROP TABLE #wmsorder
【讨论】:
我正在一一删除行,因为我正试图摆脱我使用的行。 我明白了。在这种情况下,您可能需要重新考虑整个脚本。您可能会找到一种基于集合的方式来处理您对这些数据所做的任何事情,而不是逐个使用行。【参考方案2】:DECLARE @t TABLE (a INT PRIMARY KEY)
INSERT INTO @t
VALUES (1), (2), (3)
变体 #1:
label:
DELETE TOP(1)
FROM @t
OUTPUT DELETED.a
IF @@ROWCOUNT > 0
GOTO label
变体 #2:
WHILE @@ROWCOUNT != 0
DELETE TOP(1)
FROM @t
OUTPUT DELETED.a
变体 #3:
DECLARE @a TABLE(a INT)
WHILE @@ROWCOUNT != 0 BEGIN
DELETE FROM @a
DELETE TOP(1)
FROM @t
OUTPUT DELETED.a INTO @a
SELECT * FROM @a
END
【讨论】:
这是最快的吗?我从来没想过这种方法 @ayilmaz,迭代处理总是很慢【参考方案3】:请参阅下面的代码。我刚刚更正了你分享的SQL语句
WHILE 1=1
BEGIN
IF NOT EXISTS (SELECT 1 FROM #wmsorder)
BREAK
SELECT TOP 1 @WAOR_CODE = WAOR_.WAOR_CODE
,@WAOD_INVENTORYITEMID = WAOD_.WAOD_INVENTORYITEMID
FROM #wmsorder WAOR_
SELECT @WAOR_CODE
,@WAOD_INVENTORYITEMID
DELETE #wmsorder WHERE WAOR_CODE = @WAOR_CODE AND WAOD_INVENTORYITEMID = @WAOD_INVENTORYITEMID
END
但正如 Zohar Peled 所提到的,如果您从表中逐个删除记录,这将对引擎造成痛苦。所以下面我分享了另一个查询,通过这个,你甚至可以在从表中删除之前跟踪记录
DECLARE @TableVar AS TABLE (WAOR_CODE VARCHAR(100), WAOD_INVENTORYITEMID VARCHAR(100))
WHILE 1=1
BEGIN
SELECT TOP 1 @WAOR_CODE = WAOR_.WAOR_CODE
,@WAOD_INVENTORYITEMID = WAOD_.WAOD_INVENTORYITEMID
FROM #wmsorder WAOR_
WHERE NOT EXISTS (SELECT 1 FROM @TableVar t WHERE t.WAOR_CODE = WAOR_.WAOR_CODE AND t.WAOD_INVENTORYITEMID = WAOR_.WAOD_INVENTORYITEMID)
IF @WAOR_CODE IS NULL AND @WAOD_INVENTORYITEMID IS NULL
BREAK
INSERT INTO @TableVar
(WAOR_CODE, WAOD_INVENTORYITEMID)
SELECT @WAOR_CODE
,@WAOD_INVENTORYITEMID
END
DELETE #wmsorder WHERE EXISTS (SELECT 1 FROM @TableVar t WHERE t.WAOR_CODE = #wmsorder.WAOR_CODE AND t.WAOD_INVENTORYITEMID = #wmsorder.WAOD_INVENTORYITEMID)
抱歉,我没有测试第二个代码。如果它破坏了某些东西,请原谅我。但我很确定它可能需要进行小修复才能使此查询正常运行。一切顺利。
【讨论】:
以上是关于如何在 SQL Server 的 While 循环中设置变量的主要内容,如果未能解决你的问题,请参考以下文章
如何删除 MS SQL Server 存储过程中的 While 循环? [关闭]