20.2. 存储程序的语法

存储程序和函数是用CREATE PROCEDURE和CREATE FUNCTION语句创建的子程序。一个子程序要么是一个程序要么是一个函数。使用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 PROCEDURECREATE 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也没有给定NOT DETERMINISTIC,默认的就是NOT DETERMINISTIC。

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

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

一些特征提供子程序使用数据的内在信息。CONTAINS SQL表示子程序不包含读或写数据的语句。NO SQL表示子程序不包含SQL语句。READS SQL 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 PROCEDUREALTER 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 PROCEDUREDROP FUNCTION

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
   
     
      

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

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

20.2.4. SHOW CREATE PROCEDURESHOW 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 STATUSSHOW 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局部变量

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条件

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 (1);
    
      
       
    ->   SET @x = 2;
    
      
       
    ->   INSERT INTO test.t VALUES (1);
    
      
       
    ->   SET @x = 3;
    
      
       
    -> END;
    
      
       
    -> //
    
      
       
Query OK, 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. 光标

简单光标在存储程序和函数内被支持。语法如同在嵌入的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 (a,b);
   
     
      
       ELSE
   
     
      
          INSERT INTO test.t3 VALUES (a,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. 流程控制构造

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
    
      
       
关注编程学问公众号