DBMS_SQL.DESCRIBE_COLUMNS必须在PARSE之后调用,否则报ORA-01001;仅适用于SELECT等有结果集的语句,返回列名、类型编号及长度等元数据,需据此动态调用DEFINE_COLUMN并严格匹配类型与参数。

DBMS_SQL.DESCRIBE_COLUMNS 能拿到列名和类型,但必须先 PARSE
没调用 PARSE 就直接 DESCRIBE_COLUMNS 会报 ORA-01001: invalid cursor。游标必须处于“已解析”状态,否则元数据不可读。常见错误是打开游标后跳过 PARSE,或把 DDL 语句(比如 CREATE TABLE)传给它——DESCRIBE_COLUMNS 只对带结果集的查询(SELECT、WITH、CURSOR 表达式)有效。
实际流程必须是:OPEN_CURSOR → 构造 SQL 字符串 → PARSE(第三个参数固定用 DBMS_SQL.NATIVE)→ 才能调用 DESCRIBE_COLUMNS。
- SQL 字符串不能含语法错误,哪怕只是多一个空格或引号不匹配,
PARSE就失败 - 表名、列名大小写敏感:如果建表时用了双引号(如
"MyTable"),SQL 中也得带引号;否则默认转大写 -
DESCRIBE_COLUMNS返回的col_type是 Oracle 内部编号(如 1=VARCHAR2,2=NUMBER,12=DATE),不是字符串名
DEFINE_COLUMN 必须按 col_type 分支处理,不能硬编码类型
动态查询的列结构未知,就不能像静态 SQL 那样直接写 define_column(v_cursor, 1, v_id)。你得遍历 desc_tab,根据每列的 col_type 和 col_max_len 动态声明接收变量,并调用对应 define_column 重载版本。
比如 col_type = 1(VARCHAR2)要传长度参数:dbms_sql.define_column(v_cursor, i, v_str, desctab(i).col_max_len);而 col_type = 2(NUMBER)不能传长度,否则报 ORA-06502;col_type = 12(DATE)则只传两个参数。
- 忽略
col_max_len直接传固定长度(如 100)可能截断长文本,尤其遇到 CLOB 或 XMLTYPE 列时更危险 - 没处理
col_type = 112(CLOB)或= 113(BLOB)会触发 ORA-06504:PL/SQL: Return types of Result Set variables or query do not match - 定义列数量必须和查询实际列数一致,少定义一列,
FETCH_ROWS后COLUMN_VALUE会报 ORA-01002:fetch out of sequence
FETCH_ROWS + COLUMN_VALUE 循环里不能复用同一组变量名
如果你只声明了 v_str VARCHAR2(4000)、v_num NUMBER、v_date DATE 各一个,然后在循环中反复调用 COLUMN_VALUE 给它们赋值——那所有列都会挤进同一个变量,后写的覆盖前写的,最终输出全是最后一列的值。
正确做法是:要么为每一列单独声明变量(适合列数固定且不多),要么用 PL/SQL 关联数组(TYPE t_str_tab IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER)配合动态索引存值。后者更通用,但要注意数组下标从 1 开始,和 DESCRIBE_COLUMNS 的列序号对齐。
- 未初始化的变量在
COLUMN_VALUE赋值前是 NULL,若某列允许为空,这个 NULL 会被保留;但若该列非空却因类型错配没取到值,变量仍为 NULL,容易误判 -
FETCH_ROWS返回 0 表示无更多行,返回负数(如 -1)表示出错,必须检查返回值,不能只靠>0判断 - 每次
FETCH_ROWS后,必须对每一列都调一次COLUMN_VALUE,漏掉任意一列,后续 fetch 会失败
DBMS_SQL.TO_CURSOR_NUMBER 转换 REF CURSOR 时权限和生命周期受限
如果已有本地游标(REF CURSOR),想转成 DBMS_SQL 游标以便描述结构,要用 TO_CURSOR_NUMBER。但它有个硬限制:源游标必须由当前 session 打开,且不能是自治事务(AUTONOMOUS_TRANSACTION)里的游标,否则报 ORA-06508:PL/SQL: could not find program unit being called。
另外,转换后的游标和原游标共享底层资源,CLOSE_CURSOR 任一端都会使另一端失效。更隐蔽的问题是:如果原游标来自包级变量或函数返回值,而该包被重新编译过,转换可能静默失败。
-
TO_CURSOR_NUMBER不支持绑定变量再解析,它只做“快照式”转换,后续无法再BIND_VARIABLE - 转换后仍需手动
DESCRIBE_COLUMNS和DEFINE_COLUMN,它不自动完成这些步骤 - Oracle 19c 中该函数行为与 12c 一致,但若启用了
COMPATIBLE=20.0或更高,某些内部校验会更严格,容易暴露旧代码里的隐式假设
最易被忽略的是:DESCRIBE_COLUMNS 拿到的列信息不包含 NULLABLE 属性或默认值,也不反映视图定义中的表达式别名是否被重写。如果业务依赖字段可空性判断或原始别名,得额外查 ALL_TAB_COLUMNS 或 ALL_VIEWS 视图补全——DBMS_SQL 本身不提供这层抽象。











