必须用多个SYS_REFCURSOR输出参数,因Oracle PL/SQL不支持像SQL Server那样直接执行多个SELECT返回多结果集;每个游标需独立声明、显式OPEN,且不可复用同一变量多次OPEN。

必须用多个 SYS_REFCURSOR 输出参数,一个游标对应一个结果集;不能靠单个语句或批量查询实现。
为什么不能像 SQL Server 那样用多个 SELECT?
Oracle 的 PL/SQL 不支持在存储过程中直接执行多个独立的 SELECT 语句并自动返回多个结果集。客户端(如 .NET 的 OracleDataAdapter.Fill())只认 SYS_REFCURSOR 类型的输出参数,且每个游标需显式 OPEN。
常见错误现象:ORA-24338: 未执行语句句柄 —— 就是因为某个 SYS_REFCURSOR 参数声明为 OUT,但存储过程中没对它调用 OPEN ... FOR。
- 每个结果集必须绑定到独立的
OUT SYS_REFCURSOR参数 - 所有游标都必须在存储过程体中被
OPEN,哪怕只是空查询(例如OPEN cur FOR SELECT * FROM DUAL WHERE 1=0) - 不能复用同一个游标变量多次
OPEN,否则后一次会关闭前一次
怎么定义和调用带多个游标的存储过程?
推荐封装在包(PACKAGE)里,先定义游标类型,再声明过程签名:
CREATE OR REPLACE PACKAGE pkg_multi_result AS
TYPE t_cursor IS REF CURSOR;
PROCEDURE get_user_and_order(
p_user_cur OUT t_cursor,
p_order_cur OUT t_cursor,
p_user_id IN NUMBER
);
END pkg_multi_result;包体中必须分别 OPEN 两个游标:
BEGIN OPEN p_user_cur FOR SELECT id, name FROM users WHERE id = p_user_id; OPEN p_order_cur FOR SELECT order_no, amount FROM orders WHERE user_id = p_user_id; END;
调用时注意:
- .NET 中要用
OracleCommand显式添加两个OracleParameter,类型均为OracleType.Cursor,Direction = ParameterDirection.Output - 用
OracleDataAdapter.Fill(DataSet)时,它会按参数顺序把第一个游标填入DataSet.Tables[0],第二个填入DataSet.Tables[1] - 如果想控制表名,需配
TableMappings:da.TableMappings.Add("Table", "Users")
容易被忽略的兼容性与资源问题
多个游标虽然能返回多个结果集,但它们共享同一数据库连接上下文,且全部在存储过程退出时由 Oracle 自动关闭 —— 这点和手动管理的游标不同,不必也**不能**在 PL/SQL 里写 CLOSE。
但要注意:
- 如果某个游标
OPEN后抛异常(比如NO_DATA_FOUND),该游标仍处于打开状态,可能导致连接泄漏;建议用BEGIN...EXCEPTION...END包裹每个OPEN - .NET 客户端读取完
DataSet后,OracleConnection关闭时会清理游标,但若连接池复用,残留未读游标可能引发下次调用失败 - 不要试图在一个游标里拼接多个
UNION ALL来“模拟”多结果集 —— 它仍是单个结构化结果,列数/类型必须一致,无法替代真正分离的表
最易踩的坑不是语法,而是忘了给每个 OUT SYS_REFCURSOR 都配一句 OPEN;哪怕逻辑分支里某游标不该有数据,也要 OPEN 一个空结果集,否则客户端拿不到表结构,Fill() 会直接报错。


















