SSMS中SQL循环临时表时变量赋值与表数据不匹配问题
问题根因
变量赋值和预期不符是三个逻辑漏洞共同导致的:
- 所有取
TOP 1、删TOP 1的操作都只按TableWithBins字段排序,但临时表内3条记录的TableWithBins值完全一致,都是TBL_Crocodile。当ORDER BY的排序键没有区分度时,SQL Server不会保证返回结果遵循插入顺序,每次取数、删数的目标行都是随机的。 - 三个循环变量分三次独立执行
SELECT TOP 1赋值,三次查询在排序键重复的场景下,可能匹配到不同行的字段,直接导致变量值错位。 - 删除逻辑仅以
TableWithBins作为匹配条件,会随机删除表名相同的任意一行,无法保证删除的是刚读取的那条记录。
修复方案
- 给临时表添加自增主键作为唯一排序标识,彻底解决排序结果不确定的问题
- 单条查询一次性读取当前行的所有字段赋值给变量,避免多次独立查询匹配到不同行
- 删除记录时以自增主键作为匹配条件,精准删除当前处理完成的行
修复后可直接运行的代码如下:
DECLARE @TagNumber VARCHAR(255) = 'LEC11500', @BinFrom VARCHAR(255) = 'D5', @BinTo VARCHAR(255) = 'D6' BEGIN CREATE TABLE #ListofTables ( RowID INT IDENTITY(1,1) PRIMARY KEY, 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, @CurrentRowID INT, @TableWithBins VARCHAR(255), @BinOrBinNumber VARCHAR(255), @TagNamingConvention VARCHAR(255); SET @Count = (SELECT COUNT(TableWithBins) FROM #ListofTables) WHILE(@Count > 0) BEGIN SELECT TOP 1 @CurrentRowID = RowID, @TableWithBins = TableWithBins, @TagNamingConvention = TagColomnName, @BinOrBinNumber = BinOrBinNumber FROM #ListofTables ORDER BY RowID PRINT @TableWithBins PRINT @TagNamingConvention PRINT @BinOrBinNumber SELECT * FROM #ListofTables SELECT @SQL = 'UPDATE ' + @TableWithBins + ' SET ' + @BinOrBinNumber + ' = ''' + @BinTo + ''' WHERE ' + @BinOrBinNumber + ' = ''' + @BinFrom + ''' AND ' + @TagNamingConvention + ' = ''' + @TagNumber + ''''; DELETE FROM #ListofTables WHERE RowID = @CurrentRowID SET @TableWithBins = NULL; SET @TagNamingConvention = NULL; SET @BinOrBinNumber = NULL; SET @CurrentRowID = NULL; SET @Count -= 1 END DROP TABLE #ListofTables END
修复后三次循环中@TagNamingConvention会严格按照插入顺序依次取值为CarcassTagNumber、DigitanTagNumber、TagNumber,不会再出现赋值错位问题。后续如果需要新增其他表的更新规则,直接往临时表插入对应配置即可,循环逻辑不需要调整。
内容的提问来源于stack exchange,提问作者Deuel Ellan
相关产品推荐
相关产品推荐

