如何在Sql Server中的While循环中设置变量

时间:2016-05-17 11:28:03

标签: sql-server stored-procedures while-loop cursor

我试图在SQL SERVER中使用while循环而不是CURSOR。我正在尝试选择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

3 个答案:

答案 0 :(得分:4)

另一种选择:

WHILE EXISTS(select 1 FROM #wmsorder)
BEGIN
    DELETE TOP (1)
    FROM #wmsorder
END

然而,逐个删除表中的所有记录可能是一个性能地狱。您可能需要考虑使用TRUNCATE TABLE代替:

TRUNCATE TABLE #wmsorder

另请注意,每次删除都会写入数据库日志,而truncate table根本不会写入日志。

使用包含100,000行的临时表进行测试,逐个删除行需要9秒,而截断表立即完成:

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

答案 1 :(得分:3)

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

答案 2 :(得分:0)

  

请参阅以下代码。我刚刚更正了你分享的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)
  

抱歉,我没有测试第二个代码。如果它破坏了什么,请原谅我。但我很确定它可能需要一个小修复才能使这个查询起作用。一切顺利。