SQL Server支持原生默认参数,但必须从右向左连续定义;MySQL和PostgreSQL不支持语法级默认值,需在过程体内用IF或COALESCE模拟,且显式传NULL会覆盖业务意图。

SQL Server 支持原生默认参数,但必须从右向左连续定义;MySQL 和 PostgreSQL 不支持语法级默认值,需在过程体内用 IF 或 COALESCE 模拟,且显式传 NULL 会覆盖业务意图——这是最常踩的坑。
SQL Server 中声明默认参数的硬性顺序规则
带默认值的参数必须全部放在参数列表末尾,且不能跳过中间参数。否则会报错 Incorrect syntax near '='。
错误写法(中间参数无默认值却跟在有默认值参数之后):
CREATE PROCEDURE GetOrders @status VARCHAR(20) = 'Active', @page INT, @size INT = 10
正确写法(所有可选参数靠右、连续):
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' - 不推荐用非
NULL常量作默认值(如'Active'),因为无法区分“未传参”和“传了空字符串”,DEFAULT NULL更稳妥
MySQL 存储过程中模拟默认值的两种方式
MySQL 不支持 IN p_name VARCHAR(50) DEFAULT 'Unknown' 这类语法(虽然部分新版本文档提及,但实际执行仍报错)。必须在过程体中手动判断并赋值。
常用手法是统一声明为 IN 参数,开头用 IF ... IS NULL 赋默认值:
CREATE PROCEDURE GetUsers(IN p_role VARCHAR(50), IN p_active TINYINT) BEGIN IF p_role IS NULL THEN SET p_role = 'user'; END IF; IF p_active IS NULL THEN SET p_active = 1; END IF; SELECT * FROM users WHERE role = p_role AND active = p_active; END
- 显式传
NULL会被覆盖——如果业务允许NULL作为有效筛选条件(比如查所有角色),这个逻辑就破坏语义 - 更安全的做法是加标记参数,或改用
IFNULL(p_role, 'user')在 WHERE 中直接处理,避免修改入参值 - 不要依赖
DEFAULT关键字:即使建表字段有DEFAULT,存储过程参数本身不继承该行为
PostgreSQL 函数中使用 DEFAULT 的注意事项
PostgreSQL 的 LANGUAGE plpgsql 函数支持 DEFAULT 语法,但仅限函数(非传统意义上的“存储过程”),且调用时仍需严格按序传参。
示例:
CREATE OR REPLACE FUNCTION get_orders(
p_page INT DEFAULT 1,
p_size INT DEFAULT 20,
p_status TEXT DEFAULT 'Active'
) RETURNS TABLE(...) AS $$
BEGIN
RETURN QUERY SELECT * FROM orders
WHERE status = p_status
LIMIT p_size OFFSET (p_page - 1) * p_size;
END;
$$ LANGUAGE plpgsql;
- 调用时不能跳过中间参数:
SELECT * FROM get_orders(2, DEFAULT, 'Pending')合法,但SELECT * FROM get_orders(2, 'Pending')会把'Pending'当成p_size导致类型错误 - 不支持像 SQL Server 那样用命名参数跳过任意位置,除非改用
SELECT * FROM get_orders(p_status := 'Pending', p_page := 2)(需 PostgreSQL ≥ 14) - 如果已有同名函数但参数不同,可用函数重载,但维护成本高,一般建议保持单一签名
真正容易被忽略的点是:SQL Server 无法原生区分“调用时没传该参数”和“调用时显式传了 NULL”。所以哪怕用了 DEFAULT NULL,WHERE 条件里也得写 WHERE (@p IS NULL OR column = @p),而不是 = NULL——后者永远不成立。

















