mysql 8.0支持create procedure参数default常量默认值,但null不触发默认逻辑,需手动判断;limit/offset不接受参数,须用变量承接;跨版本兼容应统一用declare+is not null判断。

MySQL 8.0 支持在 CREATE PROCEDURE 参数声明中直接使用 DEFAULT,但仅限常量,且传 NULL 不会触发默认值——它真就按 NULL 处理。
8.0+ 原生 DEFAULT 语法能用,但只认字面常量
你可以在参数定义末尾写 DEFAULT 10 或 DEFAULT 'active',这是合法的。但以下写法全部报错:
-
DEFAULT NOW()(函数调用不被允许) -
DEFAULT @var(用户变量不行) -
DEFAULT 1 + 2(表达式不支持) -
DEFAULT NULL(语法虽通,但和“不传参”语义不同:前者显式赋NULL,后者才走默认逻辑)
另外注意调用规则:必须从右向左连续省略参数。比如 proc(a, b DEFAULT 5, c DEFAULT 10),你不能写 CALL proc(1, DEFAULT, 3)——MySQL 不认这种跳着省略的语法。
传 NULL ≠ 未传参:DEFAULT 不会 fallback
这是最容易踩坑的地方。假设你定义了:
CREATE PROCEDURE get_users(IN p_limit INT DEFAULT 20)
那么这三种调用行为完全不同:
-
CALL get_users();→p_limit= 20(触发默认值) -
CALL get_users(NULL);→p_limit=NULL(不会 fallback 到 20) -
CALL get_users(30);→p_limit= 30(显式覆盖)
如果你业务上把 NULL 当作“未提供”,就得在过程体里手动判断:IF p_limit IS NULL THEN SET v_limit = 20; ELSE SET v_limit = p_limit; END IF;
LIMIT / OFFSET 后不能直接用参数或函数,必须用变量承接
哪怕你用了 DEFAULT,也不能这么写:
SELECT * FROM users LIMIT p_limit OFFSET p_offset;
因为 LIMIT 后只接受字面量或**已声明的局部变量**,不接受参数名本身。更危险的是,如果 p_limit 是 NULL,LIMIT NULL 会直接报 ERROR 1064。
正确做法是:
- 先
DECLARE v_limit INT DEFAULT 20; - 再用
IF p_limit IS NOT NULL THEN SET v_limit = p_limit; END IF; - 最后
SELECT ... LIMIT v_limit OFFSET v_offset;
这个变量承接步骤不能省——它既是兼容性兜底,也是运行时安全屏障。
跨版本兼容写法:DECLARE + IS NOT NULL 判断最稳
如果你的代码要跑在 5.7 和 8.0 混合环境,或者团队还没统一升级,别依赖 DEFAULT 关键字。统一用这个模式:
DELIMITER $$<br>CREATE PROCEDURE list_users(IN p_offset INT, IN p_limit INT)<br>BEGIN<br> DECLARE v_limit INT DEFAULT 10;<br> IF p_limit IS NOT NULL THEN<br> SET v_limit = p_limit;<br> END IF;<br> SELECT * FROM users LIMIT v_limit OFFSET p_offset;<br>END$$<br>DELIMITER ;
关键点:
-
DECLARE必须在所有SET/IF之前,否则报ERROR 1064 - 永远用
IS NOT NULL,别写= NULL(MySQL 中NULL = NULL恒为FALSE) - 字符串参数要额外处理空串:
TRIM(p_name) != ''才算“有值”
这个写法在 5.7、8.0、甚至 8.4 都完全有效,没有隐含版本陷阱。











