DBMS_SQL.RETURN_RESULT是Oracle 12c引入的隐式结果集返回机制,用于跳过OUT SYS_REFCURSOR参数绑定,直接将已打开游标推送给兼容客户端;它不提升性能、不替代动态SQL执行、不支持分页或嵌套调用,仅简化T-SQL迁移场景下的多结果集输出。
oracle 12c 的 dbms_sql.return_result 不是“更好用”,而是解决了一个具体迁移痛点:让 pl/sql 存储过程能像 sql server 的 t-sql 那样隐式返回多个结果集,无需客户端预先声明 out sys_refcursor 参数。
DBMS_SQL.RETURN_RESULT 是什么,不是什么
它不是替代 DBMS_SQL 包的通用动态 SQL 执行能力,也不是增强性能的机制。它只是一个“结果投递开关”——只负责把已打开的 SYS_REFCURSOR 实例直接推给客户端,跳过传统 OUT 参数绑定流程。
- 不改变游标打开逻辑:仍需
OPEN l_cursor FOR ...,只是后续不用RETURN l_cursor或OUT声明 - 不支持流式或分页控制:整个结果集一次性发送,无法暂停、跳过或限制行数
- 不兼容老客户端:SQL*Plus 12c+、JDBC 12.1+、ODP.NET 12.1+ 才识别隐式结果;11g 客户端连上 12c 数据库也收不到
- 不能嵌套调用:不能在另一个
DBMS_SQL游标执行过程中调用它;它只作用于当前 PL/SQL 执行上下文
为什么从 T-SQL 迁移时它显得“更简单”
因为 T-SQL 存储过程中允许裸写 SELECT,客户端自动接收结果集。而 Oracle 11g 及之前必须显式定义 OUT SYS_REFCURSOR,客户端还得逐个 registerOutParameter(..., Types.OTHER) 绑定——这在 Java/.NET 中容易漏配、顺序错乱、类型不匹配。
- 迁移旧 T-SQL 过程时,只需把
SELECT ...包进OPEN ... FOR+DBMS_SQL.RETURN_RESULT,不用改调用方代码结构 - 一个过程可发多个结果集,
DBMS_SQL.GET_NEXT_RESULT在 JDBC 中对应ResultSet.nextResult(),比维护多个命名游标更线性 - 避免了游标变量名冲突问题:传统方式中多个
OUT参数必须重命名(rc1,rc2),而隐式方式只管开、不管名 - 但注意:SQL*Plus 中会按执行顺序编号显示
ResultSet #1、ResultSet #2,没有别名,调试时靠位置判断
GaussDB 等不支持该特性的数据库怎么应对
不是“降级写法”,而是回归 Oracle 11g 兼容模式:用明确的 OUT SYS_REFCURSOR 参数替代隐式返回。关键点不在语法,而在调用链适配。
- 存储过程签名必须修改:增加带唯一名字的
OUT参数,如p_emp_result OUT SYS_REFCURSOR、p_dept_result OUT SYS_REFCURSOR - 原
DBMS_SQL.RETURN_RESULT(l_cursor)行直接删掉或注释,改为OPEN p_emp_result FOR SELECT ... - 客户端代码必须同步更新:JDBC 需要
CallableStatement.registerOutParameter(2, Types.OTHER)并按序调用getResultSet() - 不能复用同名变量:GaussDB 不支持
l_cursor多次OPEN后反复RETURN_RESULT,所以每个结果集必须配独立游标变量和 OUT 参数
真正容易被忽略的是客户端兼容性边界——DBMS_SQL.RETURN_RESULT 看似简化了服务端,实则把适配压力转移到了驱动层和应用层。一旦跨数据库迁移,别只盯着存储过程改写,先确认你用的 JDBC 版本、连接池配置、ORM 框架是否识别隐式结果集。否则过程编译通过,运行时却拿不到任何结果。


















