execute immediate 返回单行结果必须用 into;返回多行结果不可直接使用,应选用 sys_refcursor 或流水线函数。

EXECUTE IMMEDIATE 返回单行结果必须用 INTO
动态查询只返回 1 行时,EXECUTE IMMEDIATE 必须配合 INTO 子句,否则报错 ORA-00905: missing keyword 或 ORA-06550: no INTO clause。
常见错误是写成:EXECUTE IMMEDIATE 'SELECT name FROM emp WHERE id = :1' USING 123; —— 缺少 INTO,直接执行会失败。
- 变量类型需与查询列兼容,比如
name是VARCHAR2(50),接收变量也得声明为VARCHAR2(50)或用%TYPE - 如果可能无数据,必须加
EXCEPTION WHEN NO_DATA_FOUND THEN ...;如果可能多于一行,加TOO_MANY_ROWS捕获 -
USING后面的绑定变量顺序、个数必须和 SQL 中的占位符:1、:2严格一致
返回多行结果不能用 EXECUTE IMMEDIATE 直接输出
EXECUTE IMMEDIATE 本身不支持返回结果集(即多行多列),强行在 PL/SQL 块里写 SELECT ... 不会输出表格,也不会进 DBMS_OUTPUT —— 它只是语法错误或静默失败。
真正可行的路径只有两条:
- 用
OPEN ... FOR+SYS_REFCURSOR:适合从存储过程/函数向外传递结果集,调用方(如 SQL*Plus、JDBC)能直接PRINT或遍历 - 用流水线函数(
PIPELINED)+ 自定义对象类型:适合在 SQL 上下文中当作表来查,例如SELECT * FROM TABLE(my_func(123))
别试图用 EXECUTE IMMEDIATE + 循环 FETCH —— 那得先转成 DBMS_SQL,代码冗长且易出错,纯属绕路。
SYS_REFCURSOR 输出结果集最常用也最直接
这是对外暴露动态查询结果的标准方式,尤其适合封装成存储过程供应用调用。
关键点:
- 参数类型必须是
OUT SYS_REFCURSOR,不是IN,也不是普通变量 -
OPEN ... FOR后可接字符串 SQL(支持拼接)或带绑定变量的 SQL,推荐后者防注入:OPEN rc FOR sqlstr USING v_id; - 不要
CLOSE游标——调用方负责关闭;PL/SQL 块退出时未 close 也不会报错,但资源由客户端释放 - 在 SQL*Plus 中测试:先
VARIABLE rc REFCURSOR,再EXEC your_proc(:rc),最后PRINT rc
流水线函数适合嵌入 SQL 场景
当你要把动态查询“当表用”,比如和其他表 JOIN 或套在 WHERE EXISTS 里,就得走 PIPELINED 函数这条路。
必须配套三样东西:
- 一个
OBJECT类型(定义每行结构),如CREATE OR REPLACE TYPE t_row AS OBJECT (id NUMBER, name VARCHAR2(30)); - 一个
TABLE OF该对象的集合类型,如CREATE OR REPLACE TYPE t_tab AS TABLE OF t_row; - 函数声明含
RETURN t_tab PIPELINED,内部用PIPE ROW(...)逐行返回
注意:PIPELINED 函数里不能用 EXECUTE IMMEDIATE ... INTO,必须用 OPEN/FETCH/CLOSE 游标手动取值再 PIPE ROW;且 SQL 执行上下文无法捕获 PL/SQL 异常,错误会直接抛到外层。
实际用哪条路,取决于你调用它的上下文:要给 Java 程序喂数据,选 SYS_REFCURSOR;要在另一个 SQL 里当子查询用,选流水线函数。两者都绕不开显式游标,EXECUTE IMMEDIATE 在多行场景下只是个伪选项。











