Oracle 中没有 _CURSOR() 函数,正确的是 CURSOR() 游标表达式,仅能在 SELECT 列表中嵌套子查询使用,返回 REF CURSOR,需客户端显式处理,不支持视图定义或直接在 WHERE/ORDER BY 中使用。
Oracle 中 _CURSOR() 不是合法函数,别被误导
oracle 没有内置的 _cursor() 函数。你看到的可能是误传、拼写错误(比如把 cursor() 写成 _cursor()),或是某些旧版 pl/sql 工具/orm 的私有封装。真实可用的是 cursor() 表达式——它必须配合子查询使用,且只在特定上下文中合法。
-
CURSOR()是 Oracle 的游标表达式(cursor expression),用于在 SELECT 列表中返回一个嵌套游标结果集 - 它不能独立调用,也不能出现在 WHERE 或 ORDER BY 中
- 返回类型是
REF CURSOR,但客户端必须能识别并逐层打开(比如 JDBC 需用getCursor(),PL/SQL 中需用OPEN ... FOR接收) - 常见错误:
ORA-00904: "SYS"."_CURSOR": invalid identifier—— 这说明你写了不存在的函数名
正确写法:用 CURSOR() 在 SELECT 里嵌套子查询结果
典型场景是“一对多”数据扁平化时保留子集合结构,比如查部门 + 各部门员工列表。关键在于子查询必须用括号包裹,且整个 CURSOR() 表达式只能作为列值出现。
SELECT d.deptno,
d.dname,
CURSOR(SELECT e.empno, e.ename FROM emp e WHERE e.deptno = d.deptno) AS emp_list
FROM dept d;
- 子查询里的
e.deptno = d.deptno是关联条件,必须能引用外层查询的列(d.deptno) -
AS emp_list是可选别名,但建议加上,方便应用层按名字取值 - 该语句在 SQL*Plus 或 SQL Developer 中能执行,但返回的
emp_list列显示为<cursor></cursor>,需程序进一步处理 - 不支持直接在视图定义中用
CURSOR()(会报ORA-22902: CURSOR expression not allowed)
Java/JDBC 怎么读取 CURSOR() 返回的嵌套结果
JDBC 默认不自动展开游标表达式,必须显式调用 getCursor() 并重新用 ResultSet 处理。这是最容易漏掉的一步。
- 先用
rs.getObject("emp_list")获取原始对象,再强转为ResultSet - 不能直接用
rs.getString("emp_list")或其他基础类型 getter,否则抛SQLException: Invalid column type - 示例关键代码片段:
ResultSet rs = stmt.executeQuery("SELECT d.deptno, CURSOR(...) AS emp_list FROM dept d");
while (rs.next()) {
int deptno = rs.getInt("deptno");
ResultSet empRs = (ResultSet) rs.getObject("emp_list"); // ← 必须这样取
while (empRs.next()) {
System.out.println(empRs.getInt("empno"));
}
empRs.close(); // 别忘了关内层 ResultSet
}
替代方案更常用:JSON 或应用层 join,而不是硬上 CURSOR()
除非你明确需要服务端一次返回分层结构、且客户端支持 REF CURSOR(如 Oracle ADF、部分老 PL/SQL 工具),否则 CURSOR() 表达式实际价值有限。它带来几个隐性成本:
- 网络传输体积变大:每个外层行都附带一个完整子结果集,无法流式处理
- 数据库连接占用时间拉长:内层游标生命周期绑定外层 ResultSet,延迟关闭易引发连接池耗尽
- 兼容性差:MySQL / PostgreSQL / SQL Server 全都不支持类似语法,迁移成本高
- 更轻量的替代做法:用
JSON_OBJECT()+JSON_ARRAYAGG()(Oracle 12c+)生成嵌套 JSON,或干脆在应用层两次查询 + 关联组装
真正用到 CURSOR() 的地方,往往卡在遗留系统集成或特定中间件要求上。多数新项目,绕开它反而更稳。

















