MySQL 存储过程 IF 语句需写在 BEGIN…END 内,格式为 IF condition THEN … END IF;,漏 END IF 或用中文分号会报 ERROR 1064;空值判断必须用 IS NULL 而非 = NULL;变量须在 BEGIN 后显式声明并初始化。

MySQL 存储过程中 IF 语句怎么写才不报错
直接写 IF condition THEN …… END IF; 就行,但必须套在 BEGIN …… END 块里,且不能裸露在存储过程体外。常见错误是漏掉 END IF; 或把分号写成中文标点——MySQL 会报 ERROR 1064,提示语法靠近 IF 处异常。
典型场景:插入前校验用户等级,只允许 level > 0 的记录入库。
-
IF必须搭配THEN和END IF;,中间可嵌套多层IF - 条件表达式不支持赋值(如
IF @x := 1是错的),只能用布尔判断 - 分支内若需执行多条语句,必须用
BEGIN …… END包裹,单条可省略 - 注意分号是语句结束符,不是块结束符;整个存储过程定义要用
DELIMITER切换结束符
MySQL CASE 在存储过程里两种写法的区别
CASE 有表达式形式(CASE value WHEN ……)和搜索形式(CASE WHEN condition THEN ……)。前者适合等值匹配,后者更灵活,能写任意布尔表达式。别混用:表达式形式里写 WHEN x > 5 会直接报错,因为 x > 5 不是值。
性能上没差别,但可读性差异大。比如按订单状态做不同处理,用搜索形式更直观:
CASE WHEN order_status = 'pending' THEN SET action = 'notify'; WHEN order_status IN ('shipped', 'delivered') THEN SET action = 'close'; ELSE SET action = 'ignore'; END CASE;
- 表达式形式要求
value和每个WHEN后的值类型兼容,隐式转换可能出人意料 - 搜索形式每个
WHEN是独立条件,顺序重要——第一个为真就执行对应分支,后续忽略 - 必须有
ELSE或确保所有路径覆盖,否则NULL值会导致分支未定义行为
存储过程里用 IF 做空值判断为什么总进错分支
因为 IF var IS NULL 和 IF var = NULL 完全不同:= NULL 永远返回 UNKNOWN,不会进 THEN;必须用 IS NULL 或 IS NOT NULL。这是 SQL 三值逻辑的坑,不是 MySQL 特有,但新手极易栽。
常见于从查询结果赋值后判断,比如 SELECT COUNT(*) INTO @cnt FROM t WHERE id = ?;,然后 IF @cnt = 0 是对的,但 IF @cnt = NULL 就永远不成立。
- 数值比较用
=、>等,空值判断只认IS [NOT] NULL -
IFNULL()或COALESCE()可提前兜底,避免分支里反复判空 - 从
SELECT …… INTO赋值时,若无匹配行,变量会被设为NULL,不是 0 或空字符串
嵌套 IF 和 CASE 时作用域与变量可见性
MySQL 存储过程中变量是过程级作用域,所有 IF、CASE、循环块内部都能访问,不存在“块级变量”概念。所以不用担心内层声明的变量在外层不可见——压根不能在块里 DECLARE 新变量,所有变量必须在 BEGIN 后立即声明。
容易被忽略的是:同一个变量在不同分支里被多次 SET,但没初始化,首次使用可能是 NULL。比如分支 A 设 @msg = 'ok',分支 B 设 @msg = 'fail',但没进任一分支时 @msg 就是 NULL,后续用它拼接日志就会出问题。
- 所有变量必须在
BEGIN后、任何逻辑前用DECLARE显式声明 - 建议初始化:例如
DECLARE done INT DEFAULT 0;,避免依赖隐式NULL -
IF和CASE块本身不创建新作用域,只是控制执行流