Oracle存储过程必须用EXECUTE IMMEDIATE执行DDL,因编译阶段禁止CREATE/DROP/ALTER等语句,否则报PLS-00103;DDL隐式提交破坏事务一致性,且角色权限不生效,需显式授权。

PL/SQL编译阶段就拒绝CREATE、DROP、ALTER等DDL语句
Oracle在解析存储过程时,只要遇到CREATE TABLE、DROP INDEX这类关键字,立刻抛PLS-00103错误,根本不会进入执行阶段。这不是权限问题,也不是运行时环境问题,而是语法硬限制:DDL隐式触发COMMIT,会强行打断PL/SQL块默认的事务上下文。所以哪怕你有CREATE TABLE权限,直接写也通不过编译。
- 错误写法:
CREATE PROCEDURE p AS BEGIN CREATE TABLE t (x NUMBER); END; - 编译报错:
PLS-00103: 出现符号 "CREATE" - 真正起作用的是把DDL变成字符串,在运行时交给
EXECUTE IMMEDIATE去解析执行
必须用EXECUTE IMMEDIATE包裹DDL字符串
这是唯一合法路径。注意不是“可以”,而是“必须”——所有DDL操作(包括TRUNCATE、ALTER、CREATE INDEX)都得走这一步。字符串可以拼接变量,但不能直接嵌入字面量SQL(容易引号冲突),推荐先声明VARCHAR2变量再传入:
CREATE OR REPLACE PROCEDURE create_dynamic_table(p_table_name VARCHAR2) AS v_sql VARCHAR2(500); BEGIN v_sql := 'CREATE TABLE ' || p_table_name || ' (id NUMBER, name VARCHAR2(50))'; EXECUTE IMMEDIATE v_sql; END;
-
EXECUTE IMMEDIATE不校验表是否存在,建表前需自行检查USER_TABLES - 如果DDL里含单引号(如
COMMENT ON COLUMN),必须用两个单引号转义 - DDL执行后立即隐式提交,后续DML无法回滚到该点之前
ORA-01031“权限不足”不是因为没给角色,而是角色权限不生效
即使用户被授予RESOURCE角色(含CREATE TABLE),在存储过程中调用EXECUTE IMMEDIATE仍会报ORA-01031。原因在于:Oracle不继承角色权限到存储过程运行时上下文。解决方案只有一条——显式授予权限:
- 执行:
GRANT CREATE TABLE TO your_user;(不是GRANT RESOURCE TO ...) - 如果是创建同义词或视图,还需单独授
CREATE SYNONYM、CREATE VIEW - 跨用户操作(如
CREATE TABLE other_user.t)要额外授CREATE ANY TABLE
建完表不能立刻INSERT,必须也用EXECUTE IMMEDIATE
很多人以为建完表就能直接INSERT INTO new_table,结果报ORA-00942: 表或视图不存在。这是因为PL/SQL在编译期就做了对象依赖检查,而动态创建的表在编译时尚未存在。所有对动态表的操作(INSERT/SELECT/UPDATE)都得统一走EXECUTE IMMEDIATE,否则编译失败或运行时报错。
- 错误:
INSERT INTO t VALUES (1, 'a');→ 编译期就报错 - 正确:
EXECUTE IMMEDIATE 'INSERT INTO ' || p_table_name || ' VALUES (1, ''a'')'; - 注意字符串内单引号要双写,避免语法错误
最易忽略的一点:DDL执行是独立事务边界,它前面的DML和后面的DML天然割裂——你没法在一个事务里既建表又插入数据并整体回滚。如果业务强依赖原子性,得换思路,比如预建空表+TRUNCATE+INSERT,或者改用全局临时表。


















