oracle存储过程中不能直接写create global temporary table,因其属ddl语句,pl/sql编译器在解析阶段即报pls-00103错误;必须用execute immediate动态执行,且需注意表名唯一性、生命周期(on commit delete/preserve rows)及生产环境推荐预建表而非动态创建。

不能在存储过程中直接写 CREATE GLOBAL TEMPORARY TABLE 语句——它会报 PLS-00103: Encountered the symbol "CREATE" 错误。DDL 语句在 PL/SQL 块中不被允许,必须用 EXECUTE IMMEDIATE 动态执行。
为什么 CREATE GLOBAL TEMPORARY TABLE 不能直接写在存储过程里
Oracle 的 PL/SQL 编译器在解析阶段就拒绝 DDL(如 CREATE、DROP、ALTER),因为它们会隐式触发提交(commit),破坏事务一致性。即使你加了 AUTONOMOUS_TRANSACTION,也不能绕过语法校验这一关。
常见错误现象:
PLS-00103: Encountered the symbol "CREATE"ORA-06550: line X, column Y: PL/SQL: ORA-00900: invalid SQL statement
所以必须走动态 SQL 路线,但要注意:这不是“推荐做法”,而是权宜之计。
用 EXECUTE IMMEDIATE 创建临时表的实操要点
动态创建可行,但有明确限制和风险,不是每次调用都该重建:
- 表名必须唯一;若并发执行同一存储过程,两次
EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE t_temp ...'会抛ORA-00955: name is already used by an existing object - 建表语句里不能带分号(
;),否则报ORA-00911: invalid character - 字段定义要完整,比如
NOT NULL约束可以加,但主键、外键、索引等不能在建表时声明(全局临时表不支持) - 建议把建表逻辑抽离到初始化脚本中,由 DBA 提前执行一次,存储过程只负责
INSERT/SELECT
最小可用示例:
将音频或视频文件转录为带时间轴的歌词或字幕格式(如LRC、SRT、WebVTT、ASS、TTML),并制作卡拉OK视频。
CREATE OR REPLACE PROCEDURE proc_with_temp AS BEGIN EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE t_proc_tmp (id NUMBER, val VARCHAR2(50)) ON COMMIT DELETE ROWS'; INSERT INTO t_proc_tmp VALUES (1, ''hello''); COMMIT; -- 触发 ON COMMIT DELETE ROWS 清空 END;
ON COMMIT DELETE ROWS vs ON COMMIT PRESERVE ROWS 怎么选
这个参数决定数据生命周期,直接影响业务逻辑是否可靠:
-
ON COMMIT DELETE ROWS:事务提交后自动清空。适合单次处理流程(如计算+返回+清理),但如果你在过程中多次COMMIT,中间数据就丢了 -
ON COMMIT PRESERVE ROWS:数据保留到会话结束。适合跨多个事务的操作,比如分步填充、中间校验、最后汇总。但要注意:会话未断开前,表里数据一直存在,可能被后续调用误读
典型陷阱:
用 ON COMMIT PRESERVE ROWS 却没在过程开头 TRUNCATE TABLE 或 DELETE FROM,会导致上一次会话残留数据混入本次结果——尤其在连接池环境下,会话会被复用。
更稳妥的替代方案:提前建表 + 存储过程只操作
绝大多数生产环境应避免在存储过程中动态建表。正确姿势是:
- DBA 或部署脚本中一次性执行
CREATE GLOBAL TEMPORARY TABLE t_result (...) - 存储过程中只做
DELETE FROM t_result(或TRUNCATE TABLE t_result,需EXECUTE IMMEDIATE)、INSERT INTO t_result ...、SELECT * FROM t_result - 如果真需要“按需建表”,改用私有临时对象(Oracle 18c+ 的
PRIVATE TEMPORARY TABLE),语法是CREATE PRIVATE TEMPORARY TABLE ora$ptt_XXX,它自动命名、自动清理、无需 DDL 权限,且完全会话隔离
真正难处理的点不在语法,而在于生命周期管理:你得清楚数据什么时候该来、什么时候该走、会不会被别的逻辑意外读到。临时表不是“随便建完就扔”的玩具,它是会话状态的一部分,而状态最难调试。










