SQL 循环不设置其中一个值

SQL loop not setting one of the values

这是我在 SSMS 中的 SQL 代码。它成功循环遍历临时 table 并成功删除每一行的第一行,但是当它到达带有 TBL_Crocodile 的行时,它开始混乱并且没有正确设置变量。

DECLARE
@TagNumber VARCHAR(255) = 'LEC11500',
@BinFrom VARCHAR(255) = 'D5',
@BinTo VARCHAR(255) = 'D6'

BEGIN
CREATE TABLE #ListofTables (
    TableWithBins VARCHAR(255),
    TagColomnName VARCHAR(255),
    BinOrBinNumber VARCHAR(255));

INSERT INTO #ListofTables 
VALUES (
            'TBL_Crocodile',
            'CarcassTagNumber',
            'BinNumber'
        ),
        (
            'TBL_Crocodile',
            'DigitanTagNumber',
            'BinNumber'
        ),
        (
            'TBL_Crocodile',
            'TagNumber',
            'BinNumber'
        );

DECLARE 
 @SQL VARCHAR(500),
 @Count INT,
 @TableWithBins VARCHAR(255),
 @BinOrBinNumber VARCHAR(255),
 @TagNamingConvention VARCHAR(255);



 SET @Count = (SELECT COUNT(TableWithBins) FROM #ListofTables)
 WHILE(@Count > 0)
 BEGIN 

    SET @TableWithBins = (SELECT TOP (1) TableWithBins FROM #ListofTables ORDER BY TableWithBins)
    SET @TagNamingConvention = (SELECT TOP (1) TagColomnName FROM #ListofTables ORDER BY TablewithBins)
    SET @BinOrBinNumber = (SELECT TOP (1) BinOrBinNumber FROM #ListofTables ORDER BY TableWithBins)

    PRINT @TableWithBins
    print @TagNamingConvention
    print @BinOrBinNumber

    SELECT * FROM #ListofTables

    --Set the old binNumber to the new binNumber
    SELECT @SQL = 'UPDATE  ' + @TableWithBins + '
                    SET ' + @BinOrBinNumber + ' = ''' + @BinTo + '''
                    WHERE ' + @BinOrBinNumber + ' = ''' + @BinFrom + '''
                    AND ' + @TagNamingConvention + ' = ''' + @TagNumber + '''';
    --PRINT(@SQL);

    DELETE TOP (1) FROM #ListofTables WHERE TableWithBins = @TableWithBins
    SET @TableWithBins =  NULL;
    SET @TagNamingConvention = NULL;
    SET @BinOrBinNumber = NULL;
    SET @Count -= 1
END
    DROP TABLE #ListofTables

END

这是变量到达 TBL_Crocodile 时设置的内容。

(3 rows affected)
TBL_Crocodile
DigitanTagNumber
BinNumber

(3 rows affected)

(1 row affected)
TBL_Crocodile
TagNumber
BinNumber

(2 rows affected)

(1 row affected)
TBL_Crocodile
TagNumber
BinNumber

(1 row affected)

(1 row affected)

这是 tmp table #ListofTables,您可以在其中看到我的预期结果。我想将上面的三个变量(DigitanTagNumber、TagNumber、TagNumber)设置为下面这个结果中的行(CarcassTagNumber、DigitanTagNumber、TagNumber)。

设置的变量与 table 中显示的内容不匹配,我不确定为什么。

这是一个使用 ID INT IDENTITY 列的非游标解决方案。 请参阅代码中的注释。

DECLARE
@TagNumber VARCHAR(255) = 'LEC11500',
@BinFrom VARCHAR(255) = 'D5',
@BinTo VARCHAR(255) = 'D6'

BEGIN
CREATE TABLE #ListofTables (
    ID INT IDENTITY, -- Add unique ID column to use as iterator
    TableWithBins VARCHAR(255),
    TagColomnName VARCHAR(255),
    BinOrBinNumber VARCHAR(255));

INSERT INTO #ListofTables( TableWithBins, TagColomnName, BinOrBinNumber )
VALUES (
            'TBL_Crocodile',
            'CarcassTagNumber',
            'BinNumber'
        ),
        (
            'TBL_Crocodile',
            'DigitanTagNumber',
            'BinNumber'
        ),
        (
            'TBL_Crocodile',
            'TagNumber',
            'BinNumber'
        );

DECLARE 
    @SQL VARCHAR(500),
    -- @Count INT, -- No longer needed
    @ID INT,
    @TableWithBins VARCHAR(255),
    @BinOrBinNumber VARCHAR(255),
    @TagNamingConvention VARCHAR(255);


-- Select first record
 SET @ID = (SELECT MIN(ID) FROM #ListofTables)

 -- Loop until @ID becomes NULL
 WHILE( @ID IS NOT NULL )
 BEGIN 
    -- Set variables
    SELECT @TableWithBins = TableWithBins, @TagNamingConvention = TagColomnName, @BinOrBinNumber = BinOrBinNumber FROM #ListofTables WHERE ID = @ID

    PRINT @TableWithBins
    print @TagNamingConvention
    print @BinOrBinNumber

    SELECT * FROM #ListofTables

    --Set the old binNumber to the new binNumber
    SELECT @SQL = 'UPDATE  ' + @TableWithBins + '
                    SET ' + @BinOrBinNumber + ' = ''' + @BinTo + '''
                    WHERE ' + @BinOrBinNumber + ' = ''' + @BinFrom + '''
                    AND ' + @TagNamingConvention + ' = ''' + @TagNumber + '''';
    --PRINT(@SQL);

    -- Delete is optional
    --DELETE FROM #ListofTables WHERE ID = @ID
    -- Set next ID. Will be NULL when MAX ID reached
    SET @ID = (SELECT MIN(ID) FROM #ListofTables WHERE ID > @ID )

    SET @TableWithBins =  NULL;
    SET @TagNamingConvention = NULL;
    SET @BinOrBinNumber = NULL;
END

DROP TABLE #ListofTables

END

据我了解您的过程,处理行的顺序原则上无关紧要。处理每一行很重要,而且只处理一次。因此我的建议是用光标。这将逐行迭代结果集,因此这些条件(即每一行,并且只有一次)会自动满足,您无需关心顺序或从输入数据中删除“正确”行。如果您从查询创建 #ListOfTables,您甚至可以摆脱这个临时 table 并只遍历查询结果。

这是一个基于游标的解决方案


-- create your list of tables here
-- ...

DECLARE tablecursor CURSOR FOR
  SELECT tablewithbins, tagcolumname, binorbinnumber
  FROM #ListofTables

DECLARE @SQL VARCHAR(500),
    @TableWithBins VARCHAR(255),
    @BinOrBinNumber VARCHAR(255),
    @TagNamingConvention VARCHAR(255);

OPEN tablecursor

FETCH NEXT FROM tablecursor
INTO @TableWithBins, @TagNamingConvention @BinOrBinNumber

WHILE @@FETCH_STATUS = 0
BEGIN
  
  SELECT @SQL = 'UPDATE  ' + @TableWithBins + '
                    SET ' + @BinOrBinNumber + ' = ''' + @BinTo + '''
                    WHERE ' + @BinOrBinNumber + ' = ''' + @BinFrom + '''
                    AND ' + @TagNamingConvention + ' = ''' + @TagNumber + '''';
  -- do whatever you need to do in the loop with the variables
  -- no need to delete anything from the #listoftables
  
  FETCH NEXT FROM tablecursor
  INTO @TableWithBins, @TagNamingConvention @BinOrBinNumber
END

CLOSE tablecursor
DEALLOCATE tablecursor

根据您必须处理的行数,这可能还会获得一些性能,因为您不需要在循环的每次迭代中都执行查询来获取要处理的下一行。这全部由顶部的单个查询处理,该查询充当游标的源。