动态游标删除记录后仍被抓取,存储过程报错Msg16929排查
问题分析与解决方案
核心问题1:游标只读导致删除报错(Msg 16929)
动态游标(DYNAMIC)默认不具备可更新权限,必须在声明游标时显式指定FOR UPDATE子句,才能允许通过游标执行数据修改操作。如果你的游标没有添加该子句,直接在循环中尝试删除临时表记录,SQL Server会判定游标为只读,触发Msg 16929错误。
核心问题2:外部删除导致游标继续遍历已删除记录
如果你的删除操作是直接针对临时表(比如DELETE FROM #temp_fuel_que WHERE FUEL_NAME IN ('GCXFTSLOSS','GCXFTSUAF'))而非通过游标语法(DELETE WHERE CURRENT OF 游标名),动态游标无法感知这种外部修改。动态游标仅会追踪通过自身执行的修改操作,外部删除不会同步到游标结果集,因此游标仍会尝试遍历原有的三条记录,导致抓取已删除的无效行。
修正方案
方案1:正确配置可更新游标并通过游标删除记录
声明游标时添加FOR UPDATE子句,使用DELETE WHERE CURRENT OF语法删除当前游标指向的行,这样游标会自动感知行删除,循环会在有效行处理完后终止:
DECLARE @FuelName VARCHAR(50) DECLARE fuel_cursor CURSOR DYNAMIC FOR SELECT FUEL_NAME FROM #temp_fuel_que FOR UPDATE -- 赋予游标更新权限 OPEN fuel_cursor FETCH NEXT FROM fuel_cursor INTO @FuelName WHILE @@FETCH_STATUS = 0 BEGIN IF @FuelName <> 'GCXFTSFUEL' BEGIN DELETE FROM #temp_fuel_que WHERE CURRENT OF fuel_cursor -- 通过游标删除当前行 END FETCH NEXT FROM fuel_cursor INTO @FuelName END CLOSE fuel_cursor DEALLOCATE fuel_cursor
方案2:避免游标,使用直接DML语句(更高效)
如果你的需求只是保留第一条记录、删除其余所有行,完全不需要游标,直接执行删除语句即可,性能远优于游标:
DELETE FROM #temp_fuel_que WHERE FUEL_NAME <> 'GCXFTSFUEL'
内容的提问来源于stack exchange,提问作者Ksam
相关产品推荐
相关产品推荐

