EXECUTE IMMEDIATE 用于动态SQL,但DDL、单行查询、多行查询及带RETURNING的DML语法与绑定方式各异:DDL必须字符串拼接且自动提交;单行查询用INTO并确保一行;多行须用BULK COLLECT或REF CURSOR;RETURNING子句中INTO需置于末尾且与列数类型匹配;运行时隐性依赖须实测验证。

直接用 EXECUTE IMMEDIATE 就能执行大多数动态 SQL,但必须分清场景:是 DDL、单行查询、多行查询,还是带返回值的 DML —— 每种情况的语法和绑定方式都不同,错一个字就报 ORA-00900 或 ORA-06502。
DDL 语句必须用 EXECUTE IMMEDIATE,不能走静态 SQL
Oracle 不允许在 PL/SQL 块里直接写 CREATE TABLE 这类 DDL。编译器会直接报错 PLS-00103。
- DDL 必须拼成字符串,然后交给
EXECUTE IMMEDIATE执行,比如:EXECUTE IMMEDIATE 'CREATE TABLE t1 (id NUMBER)' - 表名、字段名等标识符不能用绑定变量(
:1),只能字符串拼接 —— 但要注意 SQL 注入风险,建议对输入做白名单校验或调用DBMS_ASSERT函数 - DDL 执行后会自动提交,无法回滚;如果想控制事务,得用
DBMS_SQL包(但性能差很多)
EXECUTE IMMEDIATE ... INTO 只适用于单行查询
想把查询结果赋给变量,必须确保 SQL 最多返回一行,否则抛 ORA-01422(exact fetch returns too many rows)。
- 语法是:
EXECUTE IMMEDIATE sql_str INTO var1, var2 USING bind1, bind2 -
INTO后面接的是 PL/SQL 变量,不是表字段名;类型要和查询列一一匹配 - 如果不确定是否单行,先加
ROWNUM = 1或用SELECT COUNT(*)预检,别指望异常处理兜底
多行查询要用 OPEN-FOR + FETCH,不是 INTO
EXECUTE IMMEDIATE 不支持多行结果集直接进变量;硬套 INTO 会失败,BULK COLLECT INTO 是唯一合法路径,但仍有约束。
- 推荐方案:声明 REF CURSOR,用
OPEN cursor FOR sql_str USING ...,再循环FETCH - 如果真要用
BULK COLLECT,注意内存消耗 ——FETCH ... BULK COLLECT INTO比EXECUTE IMMEDIATE ... BULK COLLECT INTO更可控 -
BULK COLLECT不会自动限制条数,大数据量时记得加LIMIT n,否则可能 OOM
DML 带 RETURNING 时,INTO 和 USING 顺序不能颠倒
比如 UPDATE ... RETURNING id INTO v_id,这个 INTO 是紧跟在 RETURNING 后面的,不是整个 EXECUTE IMMEDIATE 的结尾。
- 完整写法:
EXECUTE IMMEDIATE 'UPDATE t SET x=1 WHERE y=:1 RETURNING id INTO :2' USING in_val RETURNING INTO out_val -
RETURNING INTO的变量必须出现在EXECUTE IMMEDIATE语句末尾,且不能和前面的USING混在一起 - 返回多个值时,
RETURNING INTO后面变量个数必须和RETURNING列数一致,类型也要兼容
真正容易翻车的地方不在语法本身,而在“动态”二字带来的隐性依赖:表是否存在、字段类型是否匹配、权限是否足够 —— 这些只有运行时才暴露,编译器完全不检查。写完一定要用真实数据边界值测一遍,别信“逻辑上应该没问题”。


















