Oracle存储过程仅IN参数支持DEFAULT默认值,OUT和IN OUT参数禁止设置;调用时可省略尾部默认参数或使用命名方式,但函数在SQL上下文中调用时默认值不生效。

PL/SQL 存储过程和函数不支持真正意义上的“可选参数”语法(如 Python 的 def f(x=1)),但可以通过默认值模拟实现;函数不能用 OUT 或 IN OUT 参数,所以只有存储过程能靠 IN 参数的默认值做到“调用时省略”。
存储过程中用 DEFAULT 模拟可选参数
Oracle 允许在 CREATE PROCEDURE 的 IN 参数后直接写 DEFAULT 值,调用时可跳过该参数。注意:只对 IN 有效,OUT 和 IN OUT 不允许设默认值。
常见错误现象:定义了 DEFAULT 却仍被要求传参——那是因为你用了位置传递,而 Oracle 默认按顺序匹配,跳过中间参数必须改用命名传递。
CREATE OR REPLACE PROCEDURE log_event(p_msg IN VARCHAR2, p_level IN NUMBER DEFAULT 2) AS BEGIN DBMS_OUTPUT.PUT_LINE('Level ' || p_level || ': ' || p_msg); END;- 正确调用(省略
p_level):BEGIN log_event('startup'); END; - 错误调用(位置传递跳过中间):
BEGIN log_event('startup', ); END;→ 报错ORA-06550 - 若要传第一个、跳过第二个、再传第三个(假设有三个参数),必须用命名方式:
BEGIN log_event(p_msg => 'error', p_level => 1); END;
函数里不能设默认值?其实可以,但有硬限制
函数定义中允许 IN 参数带 DEFAULT,但要注意:函数必须返回值,且只能在 SQL 或 PL/SQL 中调用;更重要的是,DEFAULT 值在 SQL 上下文中会被忽略——也就是说,SELECT my_func() FROM dual; 这样调用时,即使函数定义了 DEFAULT,Oracle 也不会自动填充,反而报 ORA-06553: PLS-307: too many declarations of 'my_func' match this call。
所以实际能稳定用默认值的场景仅限于 PL/SQL 匿名块或存储过程内部调用:
CREATE OR REPLACE FUNCTION calc_bonus(emp_id IN NUMBER DEFAULT 100) RETURN NUMBER AS bonus NUMBER; BEGIN SELECT NVL(salary * 0.1, 0) INTO bonus FROM employees WHERE employee_id = emp_id; RETURN bonus; END;- 只能这样安全调用:
DECLARE r NUMBER; BEGIN r := calc_bonus(); DBMS_OUTPUT.PUT_LINE(r); END; - 不能这样:
SELECT calc_bonus() FROM dual;→ 失败
别用 NULL 当默认值来“假装可选”
有人写 p_id IN NUMBER DEFAULT NULL,然后在过程里判断 IF p_id IS NULL THEN ...。这看似灵活,但隐患很大:
- 调用方传入真实
NULL时,逻辑无法区分“用户有意传空”还是“用户根本没传” - 如果参数类型是
NOT NULL字段 %TYPE(如p_dept_id dept.dept_id%TYPE),DEFAULT NULL直接报编译错 - 性能上多一层判断,且容易掩盖业务意图——默认值应表达明确语义(如“全部部门”“当前时间”),而不是模糊的“未指定”
真正需要多态行为?考虑重载或拆分成多个过程
当参数组合差异大(比如有的查单条、有的查范围、有的带排序),硬塞进一个带一堆 DEFAULT 的过程,会让逻辑臃肿、难维护、易出错。
更健壮的做法:
- 定义多个同名但参数签名不同的过程(需在同一包内,Oracle 支持重载)
- 或者拆成
get_emp_by_id、get_emp_by_dept、get_emp_all等语义清晰的过程 - 避免在单个过程里堆
IF p_id IS NOT NULL THEN ... ELSIF p_dept IS NOT NULL THEN ...这类分支
最常被忽略的一点:哪怕写了 DEFAULT,调用端仍需确认执行环境是否启用 SET SERVEROUTPUT ON(否则看不到 DBMS_OUTPUT 输出),且 DML 操作默认不自动提交——可选参数背后的业务逻辑,往往比语法本身更容易出岔子。


















