declare必须紧贴begin,否则直接报error 1064;mysql解析器要求所有declare语句(变量、游标、handler)必须作为begin块的第一条可执行语法单元出现,前置注释、空行或任何可执行语句均非法。

DECLARE必须紧贴BEGIN,否则直接报ERROR 1064
MySQL解析器在编译存储过程时,会先扫描整个BEGIN块,强制要求所有DECLARE语句(含变量、游标、HANDLER)必须作为该块的**第一条可执行语法单元**出现。哪怕前面只有一行注释、一个空行或SET @x = 1,都会触发ERROR 1064 (42000)——这不是运行时报错,而是语法拒绝解析。
- ✅ 正确写法:
BEGIN→DECLARE v_id INT DEFAULT 0;→ 其他逻辑 - ❌ 错误写法:
BEGIN→-- 初始化检查→DECLARE ...(注释导致报错) - ❌ 错误写法:
BEGIN→SELECT 1;→DECLARE ...(任何可执行语句前置都非法)
嵌套BEGIN END块是作用域隔离的唯一方式
MySQL没有基于缩进或花括号的作用域机制,局部变量只在它被声明的BEGIN…END块内有效。想让两个游标互不干扰,不能靠“变量名不同”或“加注释”,必须用独立块包裹:
- 外层块声明的
done1和内层块声明的done2完全隔离,不会互相覆盖 - 若把两个
CONTINUE HANDLER FOR NOT FOUND写在同一块里,第二个触发会污染第一个的done标志 - 命名标签如
BLOCK1:非必需,但能避免LEAVE目标歧义,尤其在多层循环中
局部变量不能用:=赋值,也不能用于PREPARE
DECLARE变量赋值必须用SET或SELECT ... INTO,误用:=(用户变量语法)会导致ERROR 1337;同时,这些变量无法直接参与PREPARE动态SQL,因为预编译阶段它们尚未存在:
- ✅ 正确:
SET v_count = 100;或SELECT COUNT(*) INTO v_count FROM orders; - ❌ 错误:
SET v_count := 100;(解析为表达式,报未声明变量) - ❌ 错误:
SET @sql = CONCAT('SELECT * FROM t WHERE id = ', v_id);(v_id在PREPARE时不可见,需拼接字符串或改用@变量)
@用户变量和DECLARE变量同名时,无@前缀默认指向局部变量
如果同时存在DECLARE v_name VARCHAR(32)和SET @v_name = 'global',那么代码中写SELECT v_name会取局部变量值,SELECT @v_name才取用户变量值。这种静默遮蔽极易引发逻辑错误:
- 并发调用时,
@变量会跨过程残留,而DECLARE变量每次执行都重建 - 调试时
SELECT @v_name可能显示旧值,让你误判局部变量状态 - 推荐命名规范:局部变量加
proc_前缀(如proc_user_id),彻底规避冲突
MySQL的DECLARE规则不是风格偏好,而是编译期硬约束。最易被忽略的是:BEGIN后不能有任何非DECLARE内容,包括空行和注释——这点在复制粘贴代码或IDE自动格式化时特别容易踩坑。











