sql server参数默认值必须从右向左连续定义,mysql需用if手动模拟,postgresql仅plpgsql函数支持default;三者均无法原生区分“未传参”与“传null”。

SQL Server 支持参数默认值,但必须从右向左连续定义;MySQL 和 PostgreSQL 不原生支持,默认逻辑得靠 IF 或 COALESCE 在过程体内手动模拟。
SQL Server:带默认值的参数必须放在末尾且连续
SQL Server 允许在 CREATE PROCEDURE 中直接写 = value,但顺序不能错。一旦某个参数设了默认值,它右边所有参数也必须设默认值,中间不能断开。
- 错误写法:
CREATE PROCEDURE GetOrders @status VARCHAR(20) = 'Active', @page INT, @size INT = 10→ 报错Incorrect syntax near '=',因为@page没默认值却夹在两个有默认值的参数之间 - 正确写法:
CREATE PROCEDURE GetOrders @page INT = 1, @size INT = 20, @status VARCHAR(20) = 'Active' - 调用时可省略右侧参数:
EXEC GetOrders @page = 2(@size和@status自动取默认值) - 若想跳过
@size只传@status,必须用命名参数:EXEC GetOrders @page = 1, @status = 'Pending',否则位置传参会错位
MySQL:用 IF ... IS NULL THEN SET 模拟默认值
MySQL 存储过程不识别 = default 语法,所有参数声明都只是 IN p_param TYPE,默认值逻辑全靠过程体里判断。
- 典型模式:
IF p_role IS NULL THEN SET p_role = 'user'; END IF; - 注意:如果调用方显式传了
NULL,这段逻辑会把它覆盖成默认值——业务上要明确是否允许NULL作为有效输入 - WHERE 条件别写成
role = p_role,得改成(p_role IS NULL OR role = p_role)才能兼容“未传参”场景 - 不要依赖
COALESCE(p_role, 'user')直接进 WHERE,因为COALESCE对NULL输入仍返回NULL,起不到兜底作用
PostgreSQL:函数可用 DEFAULT,但仅限 plpgsql 函数
PostgreSQL 的存储过程本质是函数,支持 DEFAULT 关键字,但仅适用于 LANGUAGE plpgsql 定义的函数,且调用时仍需严格按序传参。
- 声明示例:
CREATE FUNCTION get_users(p_role TEXT DEFAULT 'user', p_active BOOLEAN DEFAULT true) RETURNS TABLE(...) - 调用时可省略右侧参数:
SELECT * FROM get_users('admin');→p_active自动取true - 不支持跳过中间参数,比如不能只传
p_active而跳过p_role;想实现类似效果得靠函数重载,而非单个函数内设默认值 - 注意:
DEFAULT不等于NULL,传NULL仍会进入函数体,不会触发默认值逻辑
通用坑点:SQL Server 无法区分“未传参”和“传了 NULL”
这是最常被忽略的一点:SQL Server 没有机制判断调用时是漏掉了参数,还是显式传了 NULL。所以把参数默认值设为 = NULL 是常见折中方案,但 WHERE 条件必须用 @p IS NULL,不能写 @p = NULL。
- 推荐写法:
WHERE (@CustomerId IS NULL OR CustomerId = @CustomerId) - 错误写法:
WHERE @CustomerId = NULL OR CustomerId = @CustomerId→ 永远不成立,因为NULL = NULL返回UNKNOWN - 如果业务真需要区分“未传”和“传 NULL”,只能改用表值参数或 JSON 字符串打包传参,代价高,95% 场景没必要











