MySQL中的分隔符

198
我经常看到人们在使用分隔符。我自己尝试着找出分隔符是什么以及它们的作用。经过20分钟的搜索,我没有找到一个令我满意的答案。所以,我的问题是:什么是分隔符,何时应该使用它们?

1
https://www.mysqltutorial.org/mysql-stored-procedure/mysql-delimiter/ - Channa
5个回答

284

除了默认的分隔符 ;,通常在定义函数、存储过程和触发器时需要定义多条语句。你可以定义一个不同的分隔符,比如$$,用于定义整个过程的结尾,在其中,每个语句都由;结束。这样,在mysql客户端运行代码时,客户端可以确定整个过程的结束并将其作为一个单元执行,而不是执行其中的各个语句。

请注意,关键字DELIMITER只是命令行mysql客户端(和一些其他客户端)的功能,而不是MySQL语言的常规特性。如果您尝试通过编程语言API将其传递到MySQL中,它将无法正常工作。像PHPMyAdmin这样的其他客户端有其他方法指定非默认分隔符。

示例:

DELIMITER $$
/* This is a complete statement, not part of the procedure, so use the custom delimiter $$ */
DROP PROCEDURE my_procedure$$

/* Now start the procedure code */
CREATE PROCEDURE my_procedure ()
BEGIN    
  /* Inside the procedure, individual statements terminate with ; */
  CREATE TABLE tablea (
     col1 INT,
     col2 INT
  );

  INSERT INTO tablea
    SELECT * FROM table1;

  CREATE TABLE tableb (
     col1 INT,
     col2 INT
  );
  INSERT INTO tableb
    SELECT * FROM table2;
  
/* whole procedure ends with the custom delimiter */
END$$

/* Finally, reset the delimiter to the default ; */
DELIMITER ;

如果尝试在不支持的客户端使用 DELIMITER,它将会被发送到服务器,服务器将会报告语法错误。例如,使用 PHP 和 MySQLi:

$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$result = $mysqli->query('DELIMITER $$');
echo $mysqli->error;

以下是错误信息:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER $$' at line 1


5
在哪些情况下使用分隔符是有意义的?我没有完全理解。 - System.Data
5
在定义存储过程、自定义函数和触发器时,以及在MySQL命令行上作为一个单元执行多个语句时。 - Michael Berkowski
2
请注意,DELIMITER命令在PhpMyAdmin SQL中无法使用(至少某些版本)。相反,您可以将分隔符设置在SQL本身的一个单独字段中。这让我困惑了相当长的时间... :-) - Highly Irregular
@HighlyIrregular 我之前有关于PhpMyAdmin的注释 - 或许需要更明确地指出和澄清? - Michael Berkowski
很好的解释,Michael。DELIMITER关键字具有成为对用户施加不必要负担的所有方面,旨在规避MySQL客户端无法自行分段语句的愚蠢。似乎并不难认识到复合语句以ENDEND IF等终止。客户端可能能够自己做到这一点。 - davide
显示剩余5条评论

25

DELIMITER语句用于改变标准分隔符,将分号(;)更改为其他字符。这里将分隔符从分号(;)更改为双斜杠(//)。

为什么要更改分隔符?

因为我们希望将存储过程、自定义函数等整体传递给服务器,而不是让MySQL工具逐条解释每个语句。


21

当您创建一个带有BEGIN...END块的存储过程时,块内的语句由分号(;)终止。但是,CREATE PROCEDURE语句也需要一个终止符。因此,这就变得不明确了:例程体内的分号是用于终止CREATE PROCEDURE,还是终止例程体内的语句之一。

解决歧义的方法是声明一个不同的字符串(不能在例程体内出现),MySQL客户端将其识别为CREATE PROCEDURE语句的真正终止符。


4
这是最佳答案,因为它用最简单的方式正确地解释了使用DELIMITER的原因,而且没有引起任何混淆。谢谢。 - Fakhar Anwar

14

你可以使用 DELIMITER 命令告诉 mysql 客户端将语句、函数、存储过程或触发器视为一个完整的语句。通常在 .sql 文件中,你会设置不同的 DELIMITER,比如 $$。DELIMITER 命令用于更改 MySQL 命令的标准分隔符(即 ;)。由于例程(函数、存储过程或触发器)中的语句以分号 (;) 结尾,因此我们使用 DELIMITER 将它们视为一个复合语句。如果在同一文件或命令行中使用不同的例程时未定义 DELIMITER,则会出现语法错误。

请注意,你可以使用各种非保留字符来制作自己的自定义分隔符。你应该避免使用反斜杠 (\) 字符,因为那是 MySQL 的转义字符。

DELIMITER 实际上并不是 MySQL 语言命令,而是客户端命令。

示例

DELIMITER $$

/*This is treated as a single statement as it ends with $$ */
DROP PROCEDURE IF EXISTS `get_count_for_department`$$

/*This routine is a compound statement. It ends with $$ to let the mysql client know to execute it as a single statement.*/ 
CREATE DEFINER=`student`@`localhost` PROCEDURE `get_count_for_department`(IN the_department VARCHAR(64), OUT the_count INT)
BEGIN
    
    SELECT COUNT(*) INTO the_count FROM employees where department=the_department;

END$$

/*DELIMITER is set to it's default*/
DELIMITER ;

0
在MySQL中,分隔符是一个或多个字符,用于执行SQL语句,默认情况下使用分号;作为分隔符,根据文档如下所示:

如果您使用mysql客户端程序定义包含分号字符的存储程序,会出现问题。默认情况下,mysql本身将分号识别为语句分隔符,...

因此,在MySQL中,默认情况下可以使用以下SQL语句并包含分号;来运行:
                           ↓
mysql> SELECT * FROM person;
+----+-------+
| id | name  |
+----+-------+
|  1 | John  |
|  2 | David |
+----+-------+

而且,即使它们之间有一些空格,您仍然可以使用下面的SQL语句运行;
                               ↓
mysql> SELECT * FROM person    ;
+----+-------+
| id | name  |
+----+-------+
|  1 | John  |
|  2 | David |
+----+-------+

而且,当你登录时,你可以通过使用--delimiter=--delimiter将默认分隔符;更改为hello。*如果你退出登录,分隔符hello会被改回默认分隔符;
mysql -u john -p --delimiter=hello

或者:

mysql -u john -p --delimiter hello

或者,您可以使用delimiter(DELIMITER)和\d将默认分隔符;更改为hello。*您必须在delimiter(DELIMITER)和hello之间放置一个或多个空格,否则delimiter命令不会运行,如果您使用\D,则会出现错误ERROR: Unknown command '\D'.
mysql> delimiter hello

或者:

mysql> DELIMITER hello

或者:

mysql> \d hello

或者:

mysql> \dhello

或者在Windows上,您可以按照下面的示例,在my.ini中的[mysql]下设置分隔符hello。*我的回答解释了[mysql]我的回答解释了my.ini在Windows上的位置。
# "my.ini"

[mysql]
...
delimiter='hello'

然后,您可以通过将my.ini的位置设置为--defaults-file=--defaults-extra-file=来使用登录设置分隔符hello,如下所示。*--defaults-file=--defaults-extra-file=必须是第一个选项,否则会出现错误
mysql --defaults-file='C:\ProgramData\MySQL\MySQL Server 8.0\my.ini' -u john -p 

或者:

mysql --defaults-extra-file='C:\ProgramData\MySQL\MySQL Server 8.0\my.ini' -u john -p

然后,您可以使用hello运行下面的SQL语句:
                           ↓↓↓↓↓
mysql> SELECT * FROM personhello
+----+-------+
| id | name  |
+----+-------+
|  1 | John  |
|  2 | David |
+----+-------+

而且,即使它们之间有一些空格,你仍然可以运行以下SQL语句:hello
                               ↓↓↓↓↓
mysql> SELECT * FROM person    hello
+----+-------+
| id | name  |
+----+-------+
|  1 | John  |
|  2 | David |
+----+-------+

而且,如果你想再次使用分隔符“;”,你可以按照下面的示例将分隔符hello更改为;。*请务必在delimiter;之间放置一个或多个空格,否则delimiter命令将无法运行。
delimiter ;

例如,基本上,当创建一个事件时,您需要将默认分隔符;更改为$$之类的内容,然后在创建事件之后,您需要将分隔符$$改回;,如下所示。*我的答案解释了MySQL中的事件,创建事件时必须选择一个数据库,否则会出现错误
mysql> USE apple;
mysql> delimiter $$
    -> CREATE EVENT my_event
    -> ON SCHEDULE EVERY 1 DAY
    -> STARTS '2023-11-08 00:00:00'
    -> DO
    -> BEGIN
    -> SELECT * FROM person;
    -> END$$
Query OK, 0 rows affected (0.01 sec)

mysql> delimiter ;

但是,如果在创建事件时不将默认分隔符;更改为$$之类的内容,那么您将会收到如下所示的错误信息:
mysql> USE apple;
mysql> CREATE EVENT my_event
    -> ON SCHEDULE EVERY 1 DAY
    -> STARTS '2023-11-08 00:00:00'
    -> DO
    -> BEGIN
    -> SELECT * FROM person;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接