SQL%ROWCOUNT在语句未成功执行或未触发DML/SELECT操作时返回0,如UPDATE匹配0行、SELECT INTO未找到数据(抛NO_DATA_FOUND前)等;异常处理中其值仍为上一条成功语句的结果。
隐式游标执行后,SQL%ROWCOUNT 什么时候返回 0?
它不是“没查到数据”才为 0,而是“语句没执行成功”或“根本没触发 dml/select 操作”时才为 0。比如 update 匹配 0 行、delete 无匹配、select into 找不到数据(抛出 no_data_found 异常),此时 sql%rowcount 在异常发生前仍是 0;但一旦进入异常处理块,它的值不会自动重置——仍保留上一条成功语句的结果。
-
SELECT INTO报NO_DATA_FOUND时,SQL%ROWCOUNT是 0(因为没赋值成功) -
UPDATE ... WHERE 1=0后检查SQL%ROWCOUNT,得到 0 —— 这是正常行为,不是 bug - 在
EXCEPTION块里直接读SQL%ROWCOUNT,它反映的是异常发生前最后那条可执行语句的影响行数,不是当前异常语句的
SQL%ROWCOUNT 在 FOR UPDATE 和 SELECT INTO 中的行为差异
SELECT ... FOR UPDATE 是 DML 类操作(虽不改数据,但加锁),会设置 SQL%ROWCOUNT;而纯 SELECT INTO 只有在成功赋值后才更新该属性。两者都可能因无匹配行导致 SQL%ROWCOUNT = 0,但后果不同:前者只是没锁到行,后者会直接报错中断执行。
-
SELECT emp_name INTO v_name FROM emp WHERE emp_id = 999;→ 触发NO_DATA_FOUND,SQL%ROWCOUNT为 0 -
SELECT emp_name INTO v_name FROM emp WHERE emp_id = 999 FOR UPDATE;→ 同样报NO_DATA_FOUND,SQL%ROWCOUNT也为 0 - 但
SELECT * FROM emp WHERE dept_id = 999 FOR UPDATE;(无INTO)→ 不报错,SQL%ROWCOUNT为 0,后续UPDATE或DELETE用WHERE CURRENT OF会失败
用 SQL%ROWCOUNT 判断是否更新成功,为什么有时不准?
因为它只反映最近一条 SQL 语句影响的行数,不区分“逻辑成功”和“物理变更”。比如 UPDATE t SET x = x WHERE id = 1; 即使命中一行,若 x 值本来就是相同值,Oracle 实际不修改数据页,但 SQL%ROWCOUNT 仍返回 1。
- 依赖
SQL%ROWCOUNT = 1断定“数据被改了”,可能误判(值未变也算“影响”) - 批量
UPDATE后检查SQL%ROWCOUNT,只能知道有多少行被扫描并满足条件,不能确认每行新旧值是否真不同 - 想严格判断字段是否变化,得在
SET子句中显式比较,例如:SET flag = 'Y' WHERE status != 'Y'
多个隐式游标连续执行时,SQL%ROWCOUNT 怎么跟踪?
它只记住上一条执行完的 SQL 语句结果,不会累积、不会保留历史。中间穿插了 PL/SQL 赋值、IF 判断、过程调用等非 SQL 操作,不影响它的值;但只要再执行一条 SQL,它就被覆盖。
- 执行
DELETE FROM log_table WHERE ts → <code>SQL%ROWCOUNT = 120 - 接着
v_count := SQL%ROWCOUNT;→ 安全保存 - 再执行
INSERT INTO stats VALUES (...);→SQL%ROWCOUNT立即变成 1,前面的 120 彻底丢失 - 别在两条 SQL 之间不做暂存就直接写
IF SQL%ROWCOUNT > 0 THEN ...,容易读到错误上下文的值
最易被忽略的是:异常路径下 SQL%ROWCOUNT 的值来源不可靠,它取决于哪条语句“最后成功执行”,而不是你正在处理的那条。真要稳,每次关键 SQL 后立刻存到局部变量里。

















