PL/SQL使用游标改写表值执行成功但无数据变更问题求助
问题根因
你的脚本执行后没得到预期结果,是代码逻辑存在3个核心错误:
- 逻辑用错:判断到符合条件的记录时,执行的是
INSERT插入新行操作,而非UPDATE修改原有记录,原本值为'N'的行从始至终没被修改过。 - 多余声明:FOR LOOP游标循环会自动定义循环变量,你在块开头单独声明的
ttest kurzor%ROWTYPE;完全不会被用到,属于冗余代码。 - 性能浪费:游标查询了testik表全量数据再逐行判断,没有提前过滤符合条件的记录,数据量大时执行效率极低。
额外注意:如果执行DML操作后没有手动执行COMMIT;,变更只会在当前会话生效,其他查询窗口看不到修改结果,这也是很多人改完数据看不到变化的常见原因。
解决方案
推荐写法:直接用集合式UPDATE(无需游标)
逐行游标处理的性能远低于原生集合操作,这个简单更新需求完全没必要用游标,直接执行单条SQL即可:
UPDATE testik SET alcohol = 'NO' WHERE alcohol = 'N'; -- 确认更新行数符合预期后执行提交,持久化变更 COMMIT;
游标场景正确写法(适合强制要求使用游标的场景)
如果是作业要求必须通过游标实现,需要在游标声明时加FOR UPDATE子句锁定待更新行,循环内用WHERE CURRENT OF定位到当前游标指向的行做更新,不要写INSERT:
DECLARE CURSOR kurzor IS -- 提前过滤符合条件的行,加FOR UPDATE加行锁避免并发修改冲突 SELECT * FROM testik WHERE alcohol = 'N' FOR UPDATE; BEGIN FOR ttest IN kurzor LOOP UPDATE testik SET alcohol = 'NO' -- 直接定位当前游标行,不需要额外写匹配条件 WHERE CURRENT OF kurzor; END LOOP; -- 所有修改完成后统一提交 COMMIT; END; /
你之前的脚本就算执行成功,也只是新增了一堆alcohol字段为'NO'、其余字段全为空的无效记录,原本alcohol为'N'的记录没有任何改动,自然达不到预期的修改效果。
内容的提问来源于stack exchange,提问作者Filip Kotas
相关产品推荐
相关产品推荐

