DBMS_SQL.PARSE后必须用DBMS_SQL.BIND_VARIABLE绑定变量,不可混用EXECUTE IMMEDIATE;正确流程为OPEN_CURSOR→PARSE→BIND_VARIABLE→EXECUTE→DEFINE_COLUMN→FETCH_ROWS→CLOSE_CURSOR,且绑定名、类型、游标关闭均须严格匹配。
DBMS_SQL.PARSE 之后必须用 DBMS_SQL.BIND_VARIABLE 绑定,不能用 EXECUTE IMMEDIATE
动态游标绕不开 dbms_sql,但很多人误以为 parse 后直接 execute immediate 能复用变量绑定——不行。因为 dbms_sql 的上下文是独立的,execute immediate 完全不感知你之前开的游标句柄。
常见错误现象:ora-01008: not all variables bound 或静默返回空结果,其实是因为绑定根本没生效。
正确做法是全程走 dbms_sql 流程:open_cursor → parse → bind_variable(每个占位符调一次)→ execute → define_column / fetch_rows。
注意:绑定名必须和 sql 中的命名占位符完全一致(包括冒号),大小写敏感,:emp_id 和 :emp_id 是两个变量。
绑定数组要用 BIND_ARRAY,别对循环里的单个元素反复 BIND_VARIABLE
想批量插入或 in-list 查询?比如 WHERE dept_id IN (:d1, :d2, :d3),如果用 BIND_VARIABLE 循环三次,Oracle 会报 ORA-01006: bind variable does not exist——因为解析时只认声明过的占位符名,不支持“动态扩展占位符”。
正确方式是改用 BIND_ARRAY,配合 VARCHAR2 或 NUMBER 数组类型:
DECLARE<br> l_dept_ids SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST(10, 20, 30);<br>BEGIN<br> DBMS_SQL.BIND_ARRAY(l_cursor, ':dept_ids', l_dept_ids);<br>END;
但注意:
BIND_ARRAY 只支持 Oracle 10g+,且绑定名在 SQL 中必须是单个占位符(如 :dept_ids),不能写成 :d1,:d2,:d3;底层由 Oracle 自动展开为等价 in-list。
定义列类型必须匹配 SELECT 子句实际返回类型,否则 FETCH_ROWS 报 ORA-06502
DEFINE_COLUMN 不是可选步骤,漏掉或类型错配会导致 fetch 时崩溃,典型错误是 ORA-06502: PL/SQL: numeric or value error。
关键点:
- 字符串列必须用
DEFINE_COLUMN(cursor, pos, buffer, max_len),其中max_len至少等于查询中该列最大可能长度(不是定义长度) - 数字列用
DEFINE_COLUMN(cursor, pos, num_var),但注意NUMBER(10,2)和NUMBER在绑定时无区别,只要变量声明为NUMBER即可 - 日期列必须用
DEFINE_COLUMN(cursor, pos, date_var),不能用字符串变量接 - 位置
pos从 1 开始,对应 SELECT 中字段顺序,不是别名顺序
游标未 CLOSE 就重复 OPEN_CURSOR,容易触发 ORA-01000: maximum open cursors exceeded
DBMS_SQL 游标是真实占用 session 级资源的,不像隐式游标自动回收。忘记 CLOSE_CURSOR 是最隐蔽的性能坑。
常见表现:程序跑几次就卡住,查 v$open_cursor 发现大量未关闭游标,最终报 ORA-01000。
实操建议:
- 所有
OPEN_CURSOR后必须配对CLOSE_CURSOR,哪怕中间异常也要进EXCEPTION块清理 - 用
SAVEPOINT+ROLLBACK TO无法释放游标,必须显式 close - 调试时可在
DBMS_SQL.CLOSE_CURSOR前加DBMS_OUTPUT.PUT_LINE('closing ' || l_cursor)验证是否执行到










