ORA-01001源于游标状态异常,核心是OPEN/FETCH/CLOSE未闭环或错序:未OPEN即FETCH、CLOSE后仍FETCH、REF CURSOR赋值后未OPEN FOR、作用域错误或跨过程误CLOSE均会触发。
ORA-01001 不是数据库坏了,而是游标状态断了——绝大多数情况只需检查 OPEN/FETCH/CLOSE 三步是否闭环、是否错序。
这是最常见触发点:声明了游标,但漏掉 OPEN,或 OPEN 被异常跳过(比如前面有 IF 条件没满足),后续直接 FETCH 就报 ORA-01001。
FETCH 前执行 OPEN,且不能依赖“声明即可用”OPEN ... FOR
DBMS_OUTPUT.PUT_LINE('isopen? ' || v_cur%ISOPEN);,确认进入 FETCH 前返回 TRUE
游标不是可重入资源。已 CLOSE 的游标再 FETCH,或未判断 %ISOPEN 就再次 OPEN,都会导致句柄失效。
IF v_cur%ISOPEN THEN CLOSE v_cur; END IF; OPEN v_cur; 这类“保险代码”——它掩盖了逻辑混乱OPEN 都配对一个 CLOSE,且确保只执行一次;异常分支里也得检查 %ISOPEN 再关SYS_REFCURSOR 传入子过程并 CLOSE 了,主过程不能再用REF CURSOR 是变量,不是模板。给它赋新 SQL 字符串(如拼接 WHERE 条件)只是改了字符串值,不改变已打开的查询上下文。
v_cur := 'SELECT * FROM t WHERE id = :1'; → 直接 FETCH
OPEN v_cur FOR 'SELECT * FROM t WHERE id = :1' USING p_id;
OPEN ... FOR,不能复用旧句柄PL/SQL 块嵌套时,游标变量声明位置决定其生命周期。在子块声明、父块访问,或跨过程传递未初始化的 REF CURSOR,都会让数据库找不到有效句柄。
DECLARE 子块中声明游标,然后在外部 BEGIN 中操作SYS_REFCURSOR 时,确保调用方接收后立即使用,且被调用方没有提前 CLOSE
真正容易被忽略的是:ORA-01001 往往不是孤立错误,而是上游某次 CLOSE、EXCEPTION 掉落、或 COMMIT 后未重置游标状态的副产品。查问题时别只盯报错行,要顺藤摸到第一个 OPEN 和最后一个 CLOSE 之间的所有路径。