T-SQL使用While循环与Cursor游标同步表差异返回重复记录的解决
问题根因
- 插入逻辑错误:游标循环内的
INSERT语句关联了整张#LocalTempTable,每遍历1条游标记录,就会批量插入和临时表总行数相等的重复数据,是数据重复的核心原因。 - 业务逻辑不匹配:当前代码完全没有和
Target表做id关联校验,无法区分「新增记录」和「已有记录更新」两种场景,分支逻辑也和需求要求的new_row/updated_row标注规则不符。 - 性能冗余:这类数据对比场景完全可以用SQL集合操作实现,游标遍历的写法效率极低,不适合每日批量作业。
正确实现方案
不需要使用游标,直接用集合操作一次性写入结果即可:
INSERT INTO Result_Table (变更类型, id, New) -- 匹配新增记录:Source有、Target没有的id SELECT 'new_row' AS 变更类型, s.id, s.New FROM Source s LEFT JOIN Target t ON s.id = t.id WHERE t.id IS NULL UNION ALL -- 匹配更新记录:两边id都存在,且Source的New字段更新为x或y SELECT 'updated_row' AS 变更类型, s.id, s.New FROM Source s INNER JOIN Target t ON s.id = t.id WHERE s.New IN ('x','y')
如果确实需要保留游标写法做特殊逻辑扩展,修正后的游标代码如下:
DECLARE @id nvarchar(10) DECLARE @New nvarchar(100) DECLARE NewCursor CURSOR FOR SELECT [id],[New] FROM #LocalTempTable OPEN NewCursor FETCH NEXT FROM NewCursor INTO @id,@New WHILE @@FETCH_STATUS = 0 BEGIN -- 先判断id是否存在于Target表 IF NOT EXISTS (SELECT 1 FROM Target WHERE id = @id) BEGIN -- 不存在即为新增,插入1条 INSERT INTO [Result_Table] (变更类型, id, New) VALUES ('new_row', @id, @New) END ELSE IF @New IN ('x','y') BEGIN -- 存在且New字段符合条件即为更新 INSERT INTO [Result_Table] (变更类型, id, New) VALUES ('updated_row', @id, @New) END FETCH NEXT FROM NewCursor INTO @id,@New END CLOSE NewCursor DEALLOCATE NewCursor
内容的提问来源于stack exchange,提问作者Batuhan Ayhan
相关产品推荐
相关产品推荐

