SQL Server存储过程中使用两个连续非嵌套游标技术问询
关于SQL Server游标@@FETCH_STATUS = -1的详解
首先得把这个状态的本质说清楚:@@FETCH_STATUS = -1 表示你的游标在执行FETCH NEXT操作时,已经没有更多的行可以读取了——简单说就是游标已经走到结果集的末尾了。
结合你的代码场景来看
你现在的代码里用了WHILE @@FETCH_STATUS = 0来控制循环,这是SQL Server游标循环的标准写法:
- 当
FETCH NEXT成功获取到一行数据时,@@FETCH_STATUS会返回0,这时候进入循环体执行你的插入逻辑; - 当结果集里的所有行都被处理完后,下一次
FETCH NEXT就会找不到新行,此时@@FETCH_STATUS变成-1,循环条件不满足,循环就会退出。
举个实际的例子:如果AccountBalance(@fld_fy_id)返回了8条记录,那么前8次FETCH NEXT都会让状态为0,你会执行8次插入;第9次执行FETCH NEXT时,没有行可拿了,状态变为-1,循环结束。
关于这个状态的几个关键注意点
- 别漏了循环末尾的FETCH操作:你现在的代码片段里,在
INSERT之后一定要记得加上FETCH NEXT FROM cur INTO @ACCOUNT_ID, @OPBAL, @OPCRDR, @TOTALCR, @TOTALDR, @CLBAL, @CLCRDR这一行。要是忘了,@@FETCH_STATUS会一直保持0,直接导致无限循环,这是游标使用中最常见的坑之一。 - 区分-1和-2的差异:别把-1和-2搞混了,
@@FETCH_STATUS = -2表示你要获取的那一行已经不存在了(比如被其他并发事务删除了),这和-1的“没有更多行”是完全不同的场景,处理逻辑也不一样。 - 记得清理游标资源:循环结束后,一定要执行
CLOSE cur关闭游标,再执行DEALLOCATE cur释放它占用的服务器资源,避免资源泄漏。
额外的优化建议
虽然你要求用非嵌套游标,但还是提一句:如果业务逻辑允许,尽量用基于集合的操作代替游标。比如你现在的插入逻辑,完全可以改成这样:
INSERT INTO tbl_account_balance_history (fld_fy_id, fld_account_id, fld_opening_balance, fld_op_cr_dr, ...) SELECT @fld_fy_id, [Account Id], [Op. Balance], [Cr/Dr], ... FROM AccountBalance(@fld_fy_id)
这种写法不仅代码更简洁,性能也比游标循环好很多——毕竟SQL Server天生就是为集合操作优化的。
内容的提问来源于stack exchange,提问作者Nirav Parsana
相关产品推荐
相关产品推荐

