Oracle中WHERE CURRENT OF要求游标必须显式声明FOR UPDATE,否则报ORA-01001;FETCH后须立即UPDATE,中间不可有COMMIT或其他DML;多表JOIN需用FOR UPDATE OF指定目标列;且必须在PL/SQL匿名块内使用。

游标没声明 FOR UPDATE 就直接用 WHERE CURRENT OF
Oracle 要求 WHERE CURRENT OF 只能作用于显式声明为可更新的游标。如果只是写 CURSOR c1 IS SELECT ...,没加 FOR UPDATE,哪怕逻辑上只查一行,执行 UPDATE ... WHERE CURRENT OF c1 也会报 ORA-01001: invalid cursor 或静默失败(取决于版本和兼容模式)。
必须显式带上 FOR UPDATE,且不能出现在含 DISTINCT、GROUP BY、聚合函数或不可更新视图的查询中——否则会报 ORA-02014。
常见错误写法:CURSOR c1 IS SELECT id FROM orders WHERE status = 'pending' → 缺少 FOR UPDATE;正确写法:CURSOR c1 IS SELECT id FROM orders WHERE status = 'pending' FOR UPDATE。
FETCH 后没立即 UPDATE,或者中间夹了其他 DML
游标“当前行”是个瞬态位置:它只在最近一次 FETCH 成功后有效,且仅在当前事务内维持。一旦执行了另一条 UPDATE、INSERT 或 COMMIT,这个上下文就断了。
典型翻车场景:
• FETCH c1 INTO v_id 之后调用了一个写日志的存储过程(内部有 INSERT)→ 再 UPDATE ... WHERE CURRENT OF c1 报 ORA-01002: fetch out of sequence
• FETCH 后做了 COMMIT → 游标一致性读快照失效,后续 WHERE CURRENT OF 直接失效
• 在循环里把 UPDATE 写在 EXIT WHEN c1%NOTFOUND 之前,但 FETCH 已经取到末尾 → %NOTFOUND 为 TRUE,WHERE CURRENT OF 指向空行
游标用了 JOIN 却没指定 FOR UPDATE OF 字段
当游标查询涉及多表 JOIN 时,Oracle 默认只对驱动表加锁;若你试图通过 WHERE CURRENT OF 更新被驱动表字段,会报错或更新失败。
必须显式声明锁定目标列,例如:CURSOR c1 IS SELECT e.empno, d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno FOR UPDATE OF e.sal —— 这样才能安全更新 emp.sal。
如果要更新 dept.dname,就得改成 FOR UPDATE OF d.dname;想同时更新两张表?得写成 FOR UPDATE OF e.sal, d.dname。
漏掉 OF 子句不是语法错误,但会导致目标字段不可更新,WHERE CURRENT OF 表面成功,实际没生效。
在 PL/SQL 匿名块外直接用 WHERE CURRENT OF
WHERE CURRENT OF 是 PL/SQL 语句级特性,不能在 SQL*Plus 或 SQL Developer 的普通 SQL 窗口里单独执行。它必须嵌套在 BEGIN ... END; 块中,并且游标变量需在该块内声明、打开、获取、更新、关闭。
常见误操作:
• 把游标声明放在包头,UPDATE ... WHERE CURRENT OF 写在另一个匿名块里 → 游标作用域不匹配,报 invalid cursor
• 用 REF CURSOR 变量接收外部游标结果,但没在同个 PL/SQL 块里完成 OPEN/FETCH/UPDATE/CLOSE 全流程 → WHERE CURRENT OF 找不到绑定的物理游标
本质是:游标生命周期和 WHERE CURRENT OF 必须严格共处同一 PL/SQL 执行上下文。
真正难排查的不是语法错,而是“看着执行成功,数据却没变”——那大概率是 FOR UPDATE 锁定范围不对、FETCH 和 UPDATE 不在同一个事务原子段里,或者你以为更新了 A 表,其实游标只锁了 B 表。











