DECLARE必须紧贴BEGIN后立即声明,中间不能有注释、空行或任何可执行语句,否则编译时报ERROR 1064;且声明顺序须严格为变量→游标→条件处理器,错位则报ERROR 1337。

DECLARE 必须紧贴 BEGIN 后,否则直接报 ERROR 1064
MySQL 解析器在编译存储过程时,把 DECLARE 当作块的元信息处理,不是普通可执行语句。它要求所有 DECLARE(变量、游标、HANDLER)必须出现在 BEGIN 后的**第一行起连续位置**,中间不能有任何干扰:
- 哪怕一行
-- 注释或一个空行,都会触发ERROR 1064 (42000) -
SELECT 1;、SET @flag = 1;、IF ... THEN等任何可执行语句前置,都导致创建失败 - 错误不是运行时报的,是
CREATE PROCEDURE阶段就被拒绝,根本存不进去
变量、游标、HANDLER 的声明顺序不能乱
MySQL 按照固定顺序解析依赖关系,声明错位会引发 ERROR 1337(如 “Variable 'v_flag' is not declared”):
- 必须严格按顺序:所有
DECLARE 变量→ 所有DECLARE CURSOR→ 所有DECLARE CONTINUE/EXIT HANDLER - 游标定义中若引用
v_flag,那DECLARE v_flag INT;就必须出现在游标声明之前 - 如果先写
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;,再写DECLARE cur CURSOR FOR ...,就会报错
嵌套 BEGIN END 块也要各自遵守“DECLARE 最前”规则
每个 BEGIN ... END 都是一个独立作用域,但语法约束不因嵌套而放松:
- 外层块的
DECLARE对内层块不可见,内层逻辑要用变量,必须在自己的BEGIN后立刻重新DECLARE - 常见误写:
BEGIN DECLARE x INT; BEGIN SELECT x; END;—— 内层BEGIN后没声明x,SELECT x会报ERROR 1327(Undeclared variable) - 同名变量在嵌套块中会静默遮蔽(shadowing),调试时容易漏掉值被覆盖的分支
PREPARE 动态 SQL 里用不了 DECLARE 变量
这是最容易忽略的兼容性陷阱:PREPARE 和 EXECUTE 完全不认局部变量,硬塞进去等于传 NULL:
-
PREPARE stmt FROM 'SELECT * FROM t WHERE id = ?'; EXECUTE stmt USING v_id;——v_id是局部变量,语法合法但运行时参数为NULL - 必须中转成用户变量:
SET @v_id = v_id; EXECUTE stmt USING @v_id; - 拼接 SQL 用
CONCAT()时,字符串值务必套QUOTE(v_str)防注入,且要检查@sql长度是否超@@max_allowed_packet
真正卡住人的从来不是“怎么写”,而是 MySQL 把声明位置、顺序、作用域全做成硬性语法检查——写错一行注释或调换两个 DECLARE,过程就建不成功。别指望它给你提示“建议调整顺序”,它只冷冷报个 ERROR 1064 或 1337。


















