Oracle 19c 中不存在“SQL 存储过程”,必须使用 PL/SQL 块结构(含 BEGIN...END)、正确参数声明、显式事务控制、启用 DBMS_OUTPUT 调试及相应权限授权。

直接说结论:Oracle 19c 中没有“SQL 存储过程”这种东西,你写的必须是 PL/SQL 存储过程 —— 它以 SQL 语句为核心,但整体结构、变量、控制流、异常处理都依赖 PL/SQL 语法。试图只用纯 SQL(比如一堆 INSERT/UPDATE)硬套存储过程模板,会报 PLS-00103 或 ORA-06550 错误。
CREATE PROCEDURE 必须用 PL/SQL 块结构
Oracle 不接受裸 SQL 作为存储过程体。哪怕只有一条 INSERT,也必须包裹在 BEGIN ... END; 中,并以 / 结尾(尤其在 SQL*Plus 或 SQL Developer 的脚本模式下)。
-
CREATE OR REPLACE PROCEDURE后必须跟IS或AS,然后才是声明区(可选)、BEGIN - 不能省略
BEGIN和END,哪怕没变量、没异常处理 - 结尾的
/不是注释,是 SQL*Plus/SQLcl 执行命令块的触发符;在 SQL Developer 的“运行脚本”模式下也必需 - 示例(合法):
CREATE OR REPLACE PROCEDURE log_msg AS BEGIN DBMS_OUTPUT.PUT_LINE('Hello from procedure'); END; /
IN / OUT / IN OUT 参数类型不能混淆
参数方向决定数据流向和调用方式,写错会导致值不返回、编译失败或运行时 ORA-06502(PL/SQL: numeric or value error)。
-
IN是默认模式,传入值后不可在过程内被赋值(如p_id := 100会报错) -
OUT参数必须在过程内显式赋值,否则调用方收到NULL;且调用时必须传变量(不能传字面量,如'abc') -
IN OUT允许读取输入值并修改,但调用方必须传变量——常见于字符串拼接、计数器累加等场景 - 参数类型不能带精度,例如写
p_name VARCHAR2(20)❌,必须写p_name VARCHAR2✅
事务控制必须显式管理
存储过程不会自动提交。不加 COMMIT 或 ROLLBACK,DML 操作只在当前会话可见,连接断开即回滚 —— 这常被误认为“没生效”。
- 单条 DML 后不
COMMIT,其他会话查不到变更 - 建议在成功路径末尾加
COMMIT,并在EXCEPTION块中补ROLLBACK - 如果过程被另一个已开启事务的 PL/SQL 块调用,
COMMIT会提前结束整个外部事务(破坏原子性),此时应避免在过程内提交,改由调用方统一控制 - 简单示例:
CREATE OR REPLACE PROCEDURE update_salary(p_emp_id NUMBER, p_raise NUMBER) AS BEGIN UPDATE employees SET salary = salary * (1 + p_raise) WHERE employee_id = p_emp_id; IF SQL%ROWCOUNT = 0 THEN RAISE_APPLICATION_ERROR(-20001, 'Employee not found'); END IF; COMMIT; -- 显式提交 EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; END; /
调试输出需手动启用 DBMS_OUTPUT
DBMS_OUTPUT.PUT_LINE 默认不显示任何内容,不是代码没跑,而是输出被静音了。
- 在 SQL*Plus / SQLcl 中,执行前必须先运行
SET SERVEROUTPUT ON - SQL Developer 默认关闭该功能:右键脚本编辑器 → “Enable DBMS Output”,或点击工具栏小喇叭图标
- 输出缓冲区有上限(默认 1MB),大量日志可能被截断;可临时加大:
DBMS_OUTPUT.ENABLE(10000000) - 仅用于开发调试,生产环境应禁用或替换为日志表写入
真正容易被忽略的是权限与作用域问题:新用户创建存储过程前,必须被授予 CREATE PROCEDURE 权限;而过程内部访问的表,权限必须通过定义者(AUTHID DEFINER,默认)或调用者(AUTHID CURRENT_USER)明确授权 —— 这一点在跨 Schema 调用时极易出 ORA-00942(table or view does not exist)。


















