联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
在使用 OceanBase MySQL 租户开发存储过程、函数或触发器时,你大概率会碰到这样的尴尬:创建语句里明明有分号,但客户端却把它当成了语句的结束符,直接把不完整的代码发给了数据库,然后抛出一堆语法错误。DELIMITER 就是为解决这个场景而生的。
默认情况下,MySQL 客户端(以及 OBClient)使用分号(;) 作为 SQL 语句的结束符。当你输入:
SELECT 1;
SELECT 2;
客户端会识别到两个语句,分别发送并执行。
但创建一个存储过程时,体内部往往包含多条用分号结尾的语句:
CREATE PROCEDURE sp_test()
BEGIN
DECLARE a INT DEFAULT 0;
SET a = a + 1;
SELECT a;
END;
如果直接粘贴执行,客户端看到第一个分号就认为语句结束了,于是会把发给服务器,自然报错。
DELIMITER 的作用就是临时通知客户端:“从现在起,不要再用分号作为语句结束符,改用我指定的符号(比如 // 或 $$)。” 这样一来,分号就可以安全地出现在存储过程体内,整个定义作为一个完整的语句提交。
DELIMITER 是客户端命令,不是 SQL 语句,服务器端完全不认识它。
DELIMITER
用法模板:
DELIMITER //
CREATE PROCEDURE ...
BEGIN
...;
...;
END //
DELIMITER ;
三个关键点:
环境说明:本文示例基于 OceanBase 4.x MySQL 租户,客户端为 OBClient 或标准 MySQL 命令行客户端。
-- 切换分隔符为 //
DELIMITER //
CREATE PROCEDURE calc_bonus(IN emp_id INT, OUT bonus DECIMAL(10,2))
BEGIN
DECLARE salary DECIMAL(10,2);
SELECT base_salary INTO salary FROM employees WHERE id = emp_id;
IF salary > 10000 THEN
SET bonus = salary * 0.2;
ELSE
SET bonus = salary * 0.1;
END IF;
END //
-- 恢复分隔符
DELIMITER ;
-- 调用存储过程
CALL calc_bonus(101, @b);
SELECT @b;
DELIMITER $$
CREATE FUNCTION get_grade(score INT) RETURNS VARCHAR(10)
READS SQL DATA
BEGIN
DECLARE grade VARCHAR(10);
IF score >= 90 THEN SET grade = '优秀';
ELSEIF score >= 75 THEN SET grade = '良好';
ELSEIF score >= 60 THEN SET grade = '及格';
ELSE SET grade = '不及格';
END IF;
RETURN grade;
END $$
DELIMITER ;
-- 使用函数
SELECT get_grade(85);
DELIMITER //
CREATE TRIGGER update_log BEFORE UPDATE ON accounts
FOR EACH ROW
BEGIN
INSERT INTO account_logs(account_id, old_amount, new_amount, change_time)
VALUES(OLD.id, OLD.amount, NEW.amount, NOW());
END //
DELIMITER ;
在一个 SQL 脚本中连续创建多个例程时,只需在开头修改一次分隔符,最后恢复即可:
DELIMITER $$
CREATE PROCEDURE p1() BEGIN ... END$$
CREATE FUNCTION f1() RETURNS INT BEGIN ... END$$
CREATE TRIGGER trg1 ... END$$
DELIMITER ;
每个定义结束都要用新分隔符 ,否则客户端仍会把它们看作一个未完成的语句。
DELIMITER// -- 错误,客户端无法识别
DELIMITER // -- 正确
关键字和分隔符之间必须至少有一个空格(或 Tab),否则会被当成一个非法命令。
DELIMITER //
CREATE PROCEDURE demo() BEGIN SELECT 1; END //
-- 此后所有普通语句都需要用 // 结束
SELECT NOW() // -- 如果不小心用了分号,会卡住
一旦忘了 DELIMITER ;,后续的 SELECT、INSERT 等语句只能识别新分隔符。养成在每个定义脚本末尾写上 DELIMITER ; 的好习惯。
DELIMITER //
CREATE PROCEDURE wrong()
BEGIN
DELIMITER ; -- 毫无意义且会破坏客户端解析
SELECT 1;
END //
DELIMITER ;
DELIMITER是给客户端看的,不是 SQL 的一部分。写在过程体内不会被执行,反而会扰乱客户端的解析逻辑,甚至导致脚本中断。
DELIMITER 本质上是一个客户端专用的小工具,它帮你跨越“语句内分号”的陷阱,让完整的 DDL 定义准确无误地提交到数据库。在 OceanBase MySQL 租户下,掌握它只需要记住三点: