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