如何使用PL/SQL游标变量_REF CURSOR定义与动态查询返回

落涛同学_2673

落涛同学_2673

2026-03-27

778人浏览

原创

ref cursor 是指向结果集的指针,须先声明再用 open ... for 打开,不可直接赋值sql字符串;动态sql需用using传参防注入,强类型声明更安全;其作用域限于当前会话,不可跨会话或自治事务传递,且必须由调用方显式关闭以防内存泄漏。

ref cursor 变量必须先声明再打开,不能直接赋值查询字符串

很多人以为 ref cursor 像普通变量一样能直接接 sql 字符串,比如写成 my_cursor := 'select * from emp'; —— 这会报 pls-00382: expression is of wrong type。它本质是「指向结果集的指针」,不是容器,不存 sql 文本。

正确做法是用 OPEN ... FOR 语法绑定动态 SQL:

DECLARE
  TYPE emp_cur_type IS REF CURSOR;
  emp_cur emp_cur_type;
  v_deptno NUMBER := 10;
BEGIN
  OPEN emp_cur FOR 'SELECT ename, sal FROM emp WHERE deptno = :1' USING v_deptno;
  -- 后续 FETCH ...
END;
  • 动态 SQL 必须用字符串字面量或 VARCHAR2 变量,不能拼接未转义的用户输入(防注入)
  • USING 子句传参比字符串拼接安全,且支持所有数据类型(包括对象、集合)
  • 如果 SQL 固定,优先用静态游标(CURSOR c IS SELECT...),性能更好、编译期可校验

函数返回 REF CURSOR 时,类型必须显式声明为弱类型或强类型

想让函数把查询结果“吐出来”给调用方(比如 Java 的 CallableStatement),返回类型不能写 SYS_REFCURSOR 就完事——虽然 Oracle 允许,但强类型更稳,尤其涉及列名/类型校验时。

两种声明方式区别明显:

  • 弱类型:TYPE gen_refcur IS REF CURSOR; → 可打开任意查询,灵活但无结构约束
  • 强类型:TYPE emp_refcur IS REF CURSOR RETURN emp%ROWTYPE; → 打开的查询必须严格匹配 emp 表结构,否则编译报错 PLS-00386: type mismatch in function return value

示例函数(强类型):

CREATE OR REPLACE FUNCTION get_emps_by_dept(p_deptno NUMBER)
  RETURN emp_refcur
IS
  l_cur emp_refcur;
BEGIN
  OPEN l_cur FOR SELECT * FROM emp WHERE deptno = p_deptno;
  RETURN l_cur; -- 注意:不能 CLOSE,交给调用方处理
END;

调用时务必记得 FETCH 和 CLOSE,否则游标长期占用 PGA 内存。

动态 SQL 中绑定变量个数与 USING 顺序必须严格一致

写 OPEN cur FOR 'SELECT ... WHERE a = :1 AND b = :2' USING x, y; 看似简单,但实际容易翻车:

  • 占位符 :1, :2 是位置序号,不是名字,:x 这种命名写法在动态 SQL 里无效
  • USING 后的参数个数少于占位符数 → 报 ORA-01008: not all variables bound
  • 多于占位符数 → 多余参数被忽略,不报错但逻辑可能错(比如本该查 dept=10,却因参数错位查了 dept=20)
  • 参数类型不匹配(如把 DATE 当 NUMBER 传)→ 运行时报 ORA-06502 或隐式转换失败

建议:动态 SQL 超过 2 个绑定变量时,改用 DBMS_SQL(更可控)或重构为静态 + 条件分支。

REF CURSOR 不能跨会话传递,也不能在自治事务中返回给主事务

有人想把游标从一个存储过程传到另一个,甚至塞进全局临时表——不行。REF CURSOR 是会话级内存地址,只在当前 session 的 PGA 里有效。一旦 session 断开,指针就悬空,FETCH 会报 ORA-01001: invalid cursor。

常见误用场景:

  • 在自治事务(PRAGMA AUTONOMOUS_TRANSACTION)里打开游标并返回 → 主事务拿到的是已关闭或无效的游标
  • 试图把 REF CURSOR 作为参数传给远程数据库链路(DB Link)上的过程 → 不支持
  • 在包变量里缓存 REF CURSOR 并复用 → 每次必须重新 OPEN,否则报 ORA-01001

替代方案:需要共享结果集,改用全局临时表(GTTS)或集合类型(TABLE OF);需要跨会话,走中间表或消息队列。

最常被忽略的一点:REF CURSOR 的生命周期完全由打开它的 PL/SQL 块控制,调用方不 CLOSE,它就一直占着内存,直到会话结束。高并发下容易触发 ORA-01000: maximum open cursors exceeded。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4303

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

911

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1109

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6221

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3063

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6200

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

8381

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1130

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

992

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.7万人学习