当前位置: 首页 > 文档资料 > MySQL 中文手册 >

20.2. 存储程序的语法

优质
小牛编辑
129浏览
2023-12-01

20.2.1. CREATE PROCEDURE和CREATE FUNCTION

20.2.2. ALTER PROCEDURE和ALTER FUNCTION

20.2.3. DROP PROCEDURE和DROP FUNCTION

20.2.4. SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION

20.2.5. SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS

20.2.6. CALL语句

20.2.7. BEGIN ... END复合语句

20.2.8. DECLARE语句

20.2.9. 存储程序中的变量

20.2.10. 条件和处理程序

20.2.11. 光标

20.2.12. 流程控制构造

存储程序和函数是用CREATE PROCEDURE和CREATEFUNCTION语句创建的子程序。一个子程序要么是一个程序要么是一个函数。使用CALL语句来调用程序,程序只能用输出变量传回值。就像别其它函数调用一样,函数可以被从语句外调用(即通过引用函数名),函数能返回标量值。存储子程序也可以调用其它存储子程序。

在MySQL 5.1中,一个存储子程序或函数与特定的数据库相联系。这里有几个意思:

·当一个子程序被调用时,一个隐含的USE db_name 被执行(当子程序终止时停止执行)。存储子程序内的USE语句时不允许的。

·你可以使用数据库名限定子程序名。这可以被用来引用一个不在当前数据库中的子程序。比如,要引用一个与test数据库关联的存储程序p或函数f,你可以说CALL test.p()或test.f()。

·数据库移除的时候,与它关联的所有存储子程序也都被移除。

MySQL 支持非常有用的扩展,即它允许在存储程序中使用常规的SELECT语句(那就是说,不使用光标或局部变量)。这个一个查询的结果包被简单地直接送到客户端。多SELECT语句生成多个结果包,所以客户端必须使用支持多结果包的MySQL客户端库。这意味这客户端必须使用至少MySQL 4.1以来的近期版本上的客户端库。

下面一节描述用来创建,改变,移除和查询存储程序和函数的语法。

20.2.1. CREATE PROCEDURE和CREATE FUNCTION

CREATE PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body
 
CREATE FUNCTION sp_name ([func_parameter[,...]])
    RETURNS type
    [characteristic ...] routine_body
    
    proc_parameter:
    [ IN | OUT | INOUT ] param_name type
    
    func_parameter:
    param_name type
 
type:
    Any valid MySQL data type
 
characteristic:
    LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'
 
routine_body:
    Valid SQL procedure statement or statements

这些语句创建存储子程序。要在MySQL 5.1中创建子程序,必须具有CREATE ROUTINE权限,并且ALTER ROUTINE和EXECUTE权限被自动授予它的创建者。如果二进制日志功能被允许,你也可能需要SUPER权限,请参阅20.4节,“存储子程序和触发程序的二进制日志功能”。

默认地,子程序与当前数据库关联。要明确地把子程序与一个给定数据库关联起来,可以在创建子程序的时候指定其名字为db_name.sp_name

如果子程序名和内建的SQL函数名一样,定义子程序时,你需要在这个名字和随后括号中间插入一个空格,否则发生语法错误。当你随后调用子程序的时候也要插入。为此,即使有可能出现这种情况,我们还是建议最好避免给你自己的存储子程序取与存在的SQL函数一样的名字。

由括号包围的参数列必须总是存在。如果没有参数,也该使用一个空参数列()。每个参数默认都是一个IN参数。要指定为其它参数,可在参数名之前使用关键词 OUT或INOUT

注意: 指定参数为IN, OUT, 或INOUT 只对PROCEDURE是合法的。(FUNCTION参数总是被认为是IN参数)

RETURNS字句只能对FUNCTION做指定,对函数而言这是强制的。它用来指定函数的返回类型,而且函数体必须包含一个RETURN value语句。

routine_body包含合法的SQL过程语句。可以使用复合语句语法,请参阅20.2.7节,“BEGIN ... END复合语句”。复合语句可以包含声明,循环和其它控制结构语句。这些语句的语法在本章后免介绍,举例,请参阅20.2.8节,“DECLARE语句”和20.2.12节,“流程控制构造”。

CREATE FUNCTION语句被用在更早的MySQL版本上以支持UDF (自定义函数)。请参阅27.2节,“给MySQL添加新函数”。 UDF继续被支持,即使现在有了存储函数。UDF会被认为一个外部存储函数。然而,不要让存储函数与UDF函数共享名字空间。

外部存储程序的框架将在不久的将来引入。这将允许你用SQL之外的语言编写存储程序。最可能的是,第一个被支持语言是PHP,因为核心PHP引擎很小,线程安全,且可以被方便地嵌入。因为框架是公开的,它希望许多其它语言也能被支持。

如果程序或线程总是对同样的输入参数产生同样的结果,则被认为它是“确定的”,否则就是“非确定”的。如果既没有给定DETERMINISTIC也没有给定NOTDETERMINISTIC,默认的就是NOT DETERMINISTIC。

为进行复制,使用NOW()函数(或它的同义词)或RAND()函数会不必要地使得一个子程序非确定。对NOW()而言,二进制日志包括时间戳并被正确复制。RAND() 只要在一个子程序被内应用一次也会被正确复制。(你可以把子程序执行时间戳和随机数种子认为强制输入,它们在主从上是同样的。)

当前来讲,DETERMINISTIC特征被接受,但还没有被优化程序所使用。然而如果二进制日志功能被允许了,这个特征影响到MySQL是否会接受子程序定义。请参阅20.4节,“存储子程序和触发程序的二进制日志功能”。

一些特征提供子程序使用数据的内在信息。CONTAINS SQL表示子程序不包含读或写数据的语句。NO SQL表示子程序不包含SQL语句。READSSQL DATA表示子程序包含读数据的语句,但不包含写数据的语句。MODIFIES SQL DATA表示子程序包含写数据的语句。如果这些特征没有明确给定,默认的是CONTAINS SQL。

SQL SECURITY特征可以用来指定子程序该用创建子程序者的许可来执行,还是使用调用者的许可来执行。默认值是DEFINER。在SQL:2003中者是一个新特性。创建者或调用者必须由访问子程序关联的数据库的许可。在MySQL 5.1中,必须有EXECUTE权限才能执行子程序。必须拥有这个权限的用户要么是定义者,要么是调用者,这取决于SQL SECURITY特征是如何设置的。

MySQL存储sql_mode系统变量设置,这个设置在子程序被创建的时候起作用,MySQL总是强制使用这个设置来执行子程序。

COMMENT子句是一个MySQL的扩展,它可以被用来描述存储程序。这个信息被SHOW CREATE PROCEDURE和 SHOW CREATE FUNCTION语句来显示。

MySQL允许子程序包含DDL语句,如CREATE和DROP。MySQL也允许存储程序(但不是存储函数)包含SQL 交互语句,如COMMIT。存储函数不可以包含那些做明确的和绝对的提交或者做回滚的语。SQL标准不要求对这些语句的支持,SQL标准声明每个DBMS提供商可以决定是否允许支持这些语句。

存储子程序不能使用LOAD DATA INFILE。

返回结果包的语句不能被用在存储函数种。这包括不使用INTO给变量读取列值的SELECT语句,SHOW语句,及其它诸如EXPLAIN这样的语句。对于可在函数定义时间被决定要返回一个结果包的语句,发生一个允许从函数错误返回结果包的Not(ER_SP_NO_RETSET_IN_FUNC)。对于只可在运行时决定要返回一个结果包的语句, 发生一个不能在给定上下文错误返回结果包的PROCEDURE %s (ER_SP_BADSELECT)。

下面是一个使用OUT参数的简单的存储程序的例子。例子为,在程序被定义的时候,用mysql客户端delimiter命令来把语句定界符从 ;变为//。这就允许用在程序体中的;定界符被传递到服务器而不是被mysql自己来解释。

mysql> delimiter //
 
mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
    -> BEGIN
    ->   SELECT COUNT(*) INTO param1 FROM t;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)
 
mysql> delimiter ;
 
mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT @a;
+------+
| @a   |
+------+
| 3    |
+------+
1 row in set (0.00 sec)

当使用delimiter命令时,你应该避免使用反斜杠(‘\’)字符,因为那是MySQL的转义字符。

下列是一个例子,一个采用参数的函数使用一个SQL函数执行一个操作,并返回结果:

mysql> delimiter //
 
mysql> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50)
    -> RETURN CONCAT('Hello, ',s,'!');
    -> //
Query OK, 0 rows affected (0.00 sec)
 
mysql> delimiter ;
 
mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world!  |
+----------------+
1 row in set (0.00 sec)

如果在存储函数中的RETURN语句返回一个类型不同于在函数的RETURNS子句中指定类型的值,返回值被强制为恰当的类型。比如,如果一个函数返回一个ENUM或SET值,但是RETURN语句返回一个整数,对于SET成员集的相应的ENUM成员,从函数返回的值是字符串。

20.2.2. ALTER PROCEDURE和ALTER FUNCTION

ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
 
characteristic:
    { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'

这个语句可以被用来改变一个存储程序或函数的特征。在MySQL 5.1中,你必须用ALTER ROUTINE权限才可用此子程序。这个权限被自动授予子程序的创建者。如20.4节,“存储子程序和触发程序的二进制日志功能”中所述, 如果二进制日志功能被允许了,你可能也需要SUPER权限。

在ALTER PROCEDURE和ALTER FUNCTION语句中,可以指定超过一个的改变。

20.2.3. DROP PROCEDURE和DROP FUNCTION

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

这个语句被用来移除一个存储程序或函数。即,从服务器移除一个制定的子程序。在MySQL 5.1中,你必须有ALTER ROUTINE权限才可用此子程序。这个权限被自动授予子程序的创建者。

IF EXISTS 子句是一个MySQL的扩展。如果程序或函数不存储,它防止发生错误。产生一个可以用SHOW WARNINGS查看的警告。

20.2.4. SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION

SHOW CREATE {PROCEDURE | FUNCTION} sp_name

这个语句是一个MySQL的扩展。类似于SHOW CREATE TABLE,它返回一个可用来重新创建已命名子程序的确切字符串。

mysql> SHOW CREATE FUNCTION test.hello\G
*************************** 1. row ***************************
       Function: hello
       sql_mode:
Create Function: CREATE FUNCTION `test`.`hello`(s CHAR(20)) RETURNS CHAR(50)
RETURN CONCAT('Hello, ',s,'!')

20.2.5. SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS

SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']

这个语句是一个MySQL的扩展。它返回子程序的特征,如数据库,名字,类型,创建者及创建和修改日期。如果没有指定样式,根据你使用的语句,所有存储程序和所有存储函数的信息都被列出。

mysql> SHOW FUNCTION STATUS LIKE 'hello'\G
*************************** 1. row ***************************
   Db: test
 Name: hello
 Type: FUNCTION
      Definer: testuser@localhost
     Modified: 2004-08-03 15:29:37
      Created: 2004-08-03 15:29:37
Security_type: DEFINER
      Comment:

你可以从INFORMATION_SCHEMA中的ROUTINES表获得有关存储子程序的信息。请参阅23.1.14节,“INFORMATION_SCHEMA ROUTINES 表”。

20.2.6. CALL语句

CALL sp_name([parameter[,...]])

CALL语句调用一个先前用CREATE PROCEDURE创建的程序。

CALL语句可以用声明为OUT或的INOUT参数的参数给它的调用者传回值。它也“返回”受影响的行数,客户端程序可以在SQL级别通过调用ROW_COUNT()函数获得这个数,从C中是调用the mysql_affected_rows() C API函数来获得。

20.2.7. BEGIN ... END复合语句

[begin_label:] BEGIN
    [statement_list]
END [end_label]

存储子程序可以使用BEGIN ... END复合语句来包含多个语句。statement_list 代表一个或多个语句的列表。statement_list之内每个语句都必须用分号(;)来结尾。

复合语句可以被标记。除非begin_label存在,否则end_label不能被给出,并且如果二者都存在,他们必须是同样的。

请注意,可选的[NOT] ATOMIC子句现在还不被支持。这意味着在指令块的开始没有交互的存储点被设置,并且在上下文中用到的BEGIN子句对当前交互动作没有影响。

使用多重语句需要客户端能发送包含语句定界符;的查询字符串。这个符号在命令行客户端被用delimiter命令来处理。改变查询结尾定界符;(比如改变为//)使得; 可被用在子程序体中。

20.2.8. DECLARE语句

DECLARE语句被用来把不同项目局域到一个子程序:局部变量(请参阅20.2.9节,“存储程序中的变量”),条件和处理程序(请参阅20.2.10节,“条件和处理程序”) 及光标(请参阅20.2.11节,“光标”)。SIGNAL和RESIGNAL语句当前还不被支持。

DECLARE仅被用在BEGIN ... END复合语句里,并且必须在复合语句的开头,在任何其它语句之前。

光标必须在声明处理程序之前被声明,并且变量和条件必须在声明光标或处理程序之前被声明。

20.2.9. 存储程序中的变量

20.2.9.1. DECLARE局部变量

20.2.9.2. 变量SET语句

20.2.9.3. SELECT ... INTO语句

你可以在子程序中声明并使用变量。

20.2.9.1. DECLARE局部变量

DECLARE var_name[,...] type [DEFAULT value]

这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个DEFAULT子句。值可以被指定为一个表达式,不需要为一个常数。如果没有DEFAULT子句,初始值为NULL。

局部变量的作用范围在它被声明的BEGIN ... END块内。它可以被用在嵌套的块中,除了那些用相同名字声明变量的块。

20.2.9.2. 变量SET语句

SET var_name = expr [, var_name = expr] ...

在存储程序中的SET语句是一般SET语句的扩展版本。被参考变量可能是子程序内声明的变量,或者是全局服务器变量。

在存储程序中的SET语句作为预先存在的SET语法的一部分来实现。这允许SET a=x, b=y, ...这样的扩展语法。其中不同的变量类型(局域声明变量及全局和集体变量)可以被混合起来。这也允许把局部变量和一些只对系统变量有意义的选项合并起来。在那种情况下,此选项被识别,但是被忽略了。

20.2.9.3. SELECT... INTO语句

SELECT col_name[,...] INTO var_name[,...] table_expr

这个SELECT语法把选定的列直接存储到变量。因此,只有单一的行可以被取回。

SELECT id,data INTO x,y FROM test.t1 LIMIT 1;

注意,用户变量名在MySQL 5.1中是对大小写不敏感的。请参阅9.3节,“用户变量”。

重要: SQL变量名不能和列名一样。如果SELECT ... INTO这样的SQL语句包含一个对列的参考,并包含一个与列相同名字的局部变量,MySQL当前把参考解释为一个变量的名字。例如,在下面的语句中,xname 被解释为到xname variable 的参考而不是到xname column的:

CREATE PROCEDURE sp1 (x VARCHAR(5))
  BEGIN
    DECLARE xname VARCHAR(5) DEFAULT 'bob';
    DECLARE newname VARCHAR(5);
    DECLARE xid INT;
    
    SELECT xname,id INTO newname,xid 
      FROM table1 WHERE xname = xname;
    SELECT newname;
  END;

当这个程序被调用的时候,无论table.xname列的值是什么,变量newname将返回值‘bob’。

请参阅I.1节,“存储子程序和触发程序的限制”。

20.2.10. 条件和处理程序

20.2.10.1. DECLARE条件

20.2.10.2. DECLARE处理程序

特定条件需要特定处理。这些条件可以联系到错误,以及子程序中的一般流程控制。

20.2.10.1. DECLARE条件

DECLARE condition_name CONDITION FOR condition_value
 
condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | mysql_error_code

这个语句指定需要特殊处理的条件。它将一个名字和指定的错误条件关联起来。这个名字可以随后被用在DECLARE HANDLER语句中。请参阅20.2.10.2节,“DECLARE处理程序”。

除了SQLSTATE值,也支持MySQL错误代码。

20.2.10.2. DECLARE处理程序

DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement
 
handler_type:
    CONTINUE
  | EXIT
  | UNDO
 
condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | condition_name
  | SQLWARNING
  | NOT FOUND
  | SQLEXCEPTION
  | mysql_error_code

这个语句指定每个可以处理一个或多个条件的处理程序。如果产生一个或多个条件,指定的语句被执行。

对一个CONTINUE处理程序,当前子程序的执行在执行处理程序语句之后继续。对于EXIT处理程序,当前BEGIN...END复合语句的执行被终止。UNDO 处理程序类型语句还不被支持。

·SQLWARNING是对所有以01开头的SQLSTATE代码的速记。

·NOT FOUND是对所有以02开头的SQLSTATE代码的速记。

·SQLEXCEPTION是对所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE代码的速记。

除了SQLSTATE值,MySQL错误代码也不被支持。

例如:

mysql> CREATE TABLE test.t (s1 int,primary key (s1));
Query OK, 0 rows affected (0.00 sec)
 
mysql> delimiter //
 
mysql> CREATE PROCEDURE handlerdemo ()
    -> BEGIN
    ->   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
    ->   SET @x = 1;
    ->   INSERT INTO test.t VALUES (NULL, 0 rows affected (0.00 sec)
 
mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT @x//
    +------+
    | @x   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)

注意到,@x是3,这表明MySQL被执行到程序的末尾。如果DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; 这一行不在,第二个INSERT因PRIMARY KEY强制而失败之后,MySQL可能已经采取默认(EXIT)路径,并且SELECT @x可能已经返回2。

20.2.11. 光标

20.2.11.1.声明光标

20.2.11.2. 光标OPEN语句

20.2.11.3. 光标FETCH语句

20.2.11.4. 光标CLOSE语句

简单光标在存储程序和函数内被支持。语法如同在嵌入的SQL中。光标当前是不敏感的,只读的及不滚动的。不敏感意为服务器可以活不可以复制它的结果表。

光标必须在声明处理程序之前被声明,并且变量和条件必须在声明光标或处理程序之前被声明。

例如:

CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE a CHAR(16);
  DECLARE b,c INT;
  DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
  DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
 
  OPEN cur1;
  OPEN cur2;
 
  REPEAT
    FETCH cur1 INTO a, b;
    FETCH cur2 INTO c;
    IF NOT done THEN
       IF b < c THEN
  INSERT INTO test.t3 VALUES (NULL,b);
       ELSE
  INSERT INTO test.t3 VALUES (NULL,c);
       END IF;
    END IF;
  UNTIL done END REPEAT;
 
  CLOSE cur1;
  CLOSE cur2;
END

20.2.11.1.声明光标

DECLARE cursor_name CURSOR FOR select_statement

这个语句声明一个光标。也可以在子程序中定义多个光标,但是一个块中的每一个光标必须有唯一的名字。

SELECT语句不能有INTO子句。

20.2.11.2. 光标OPEN语句

OPEN cursor_name

这个语句打开先前声明的光标。

20.2.11.3. 光标FETCH语句

FETCH cursor_name INTO var_name [, var_name] ...

这个语句用指定的打开光标读取下一行(如果有下一行的话),并且前进光标指针。

20.2.11.4. 光标CLOSE语句

CLOSE cursor_name

这个语句关闭先前打开的光标。

如果未被明确地关闭,光标在它被声明的复合语句的末尾被关闭。

20.2.12. 流程控制构造

20.2.12.1. IF语句

20.2.12.2. CASE语句

20.2.12.3. LOOP语句

20.2.12.4. LEAVE语句

20.2.12.5. ITERATE语句

20.2.12.6. REPEAT语句

20.2.12.7. WHILE语句

IF, CASE, LOOP, WHILE, ITERATE, 及 LEAVE 构造被完全实现。

这些构造可能每个包含要么一个单独语句,要么是使用BEGIN ... END复合语句的一块语句。构造可以被嵌套。

目前还不支持FOR循环。

20.2.12.1. IF语句

IF search_condition THEN statement_list
    [ELSEIF search_condition THEN statement_list] ...
    [ELSE statement_list]
END IF

IF实现了一个基本的条件构造。如果search_condition求值为真,相应的SQL语句列表被执行。如果没有search_condition匹配,在ELSE子句里的语句列表被执行。statement_list可以包括一个或多个语句。

请注意,也有一个IF() 函数,它不同于这里描述的IF语句。请参阅12.2节,“控制流程函数”。

20.2.12.2. CASE语句

CASE case_value
    WHEN when_value THEN statement_list
    [WHEN when_value THEN statement_list] ...
    [ELSE statement_list]
END CASE

Or:

CASE
    WHEN search_condition THEN statement_list
    [WHEN search_condition THEN statement_list] ...
    [ELSE statement_list]
END CASE

存储程序的CASE语句实现一个复杂的条件构造。如果search_condition 求值为真,相应的SQL被执行。如果没有搜索条件匹配,在ELSE子句里的语句被执行。

注意:这里介绍的用在存储程序里的CASE语句与12.2节,“控制流程函数”里描述的SQL CASE表达式的CASE语句有轻微不同。这里的CASE语句不能有ELSE NULL子句,并且用END CASE替代END来终止。

20.2.12.3. LOOP语句

[begin_label:] LOOP
    statement_list
END LOOP [end_label]

LOOP允许某特定语句或语句群的重复执行,实现一个简单的循环构造。在循环内的语句一直重复直循环被退出,退出通常伴随着一个LEAVE 语句。

LOOP语句可以被标注。除非begin_label存在,否则end_label不能被给出,并且如果两者都出现,它们必须是同样的。

20.2.12.4. LEAVE语句

LEAVE label

这个语句被用来退出任何被标注的流程控制构造。它和BEGIN ... END或循环一起被使用。

20.2.12.5. ITERATE语句

ITERATE label

ITERATE只可以出现在LOOP, REPEAT, 和WHILE语句内。ITERATE意思为:“再次循环。”

例如:

CREATE PROCEDURE doiterate(p1 INT)
BEGIN
  label1: LOOP
    SET p1 = p1 + 1;
    IF p1 < 10 THEN ITERATE label1; END IF;
    LEAVE label1;
  END LOOP label1;
  SET @x = p1;
END

20.2.12.6. REPEAT语句

[begin_label:] REPEAT
    statement_list
UNTIL search_condition
END REPEAT [end_label]

REPEAT语句内的语句或语句群被重复,直至search_condition 为真。

REPEAT 语句可以被标注。 除非begin_label也存在,end_label才能被用,如果两者都存在,它们必须是一样的。

例如:

mysql> delimiter //
 
mysql> CREATE PROCEDURE dorepeat(p1 INT)
    -> BEGIN
    ->   SET @x = 0;
    ->   REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)
 
mysql> CALL dorepeat(1000)//
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT @x//
+------+
| @x   |
+------+
| 1001 |
+------+
1 row in set (0.00 sec)

20.2.12.7. WHILE语句

[begin_label:] WHILE search_condition DO
    statement_list
END WHILE [end_label]

WHILE语句内的语句或语句群被重复,直至search_condition 为真。

WHILE语句可以被标注。 除非begin_label也存在,end_label才能被用,如果两者都存在,它们必须是一样的。

例如:

CREATE PROCEDURE dowhile()
BEGIN
  DECLARE v1 INT DEFAULT 5;
 
  WHILE v1 > 0 DO
    ...
    SET v1 = v1 - 1;
  END WHILE;
END