zoukankan      html  css  js  c++  java
  • MySQL 5.0 新特性教程 存储历程:第三讲

     来源:网海拾贝  




    作者:mysql AB;翻译:陈朋奕

    The New SQL Statements 新SQL语句

    Variables 变量

      在复合语句中声明变量的指令是DECLARE。

      (1) Example with two DECLARE statements

      两个DECLARE语句的例子

    CREATE PROCEDURE p8 ()

    BEGIN

    DECLARE a INT;

    DECLARE b INT;

    SET a = 5;

    SET b = 5;

    INSERT INTO t VALUES (a);

    SELECT s1 * a FROM t WHERE s1 >= b;

    END; // /* I won't CALL this */
      在历程中定义的变量并不是真正的定义,你只是在BEGIN/END块内定义了而已(译注:也便是形参)。

      寄望这些变量和会话变量纷比方样,不能运用修饰符@你必须分明的在BEGIN/END块中声明变量和它们的楷模。

      变量一旦声明,你就能在任何能运用会话变量、文字、列名的地方运用。

      (2) Example with no DEFAULT clause and SET statement

      没有默许子句和设定语句的例子

    CREATE PROCEDURE p9 ()

    BEGIN

    DECLARE a INT /* there is no DEFAULT clause */;

    DECLARE b INT /* there is no DEFAULT clause */;

    SET a = 5; /* there is a SET statement */

    SET b = 5; /* there is a SET statement */

    INSERT INTO t VALUES (a);

    SELECT s1 * a FROM t WHERE s1 >= b;

    END; // /* I won't CALL this */
      有许多初始化变量的方式。如果没有默许的子句,那么变量的初始值为NULL。你可以在任何时分运用SET语句给变量赋值。

      (3) Example with DEFAULT clause

      含有DEFAULT子句的例子

    CREATE PROCEDURE p10 ()

    BEGIN

    DECLARE a, b INT DEFAULT 5;

    INSERT INTO t VALUES (a);

    SELECT s1 * a FROM t WHERE s1 >= b;

    END; //

      我们在这里做了一些窜改,可是成效照样一样的。在这里运用了DEFAULT子句来设定初始值,这就不需求把DECLARE和SET语句的完因素隔隔离分散了。

      (4) Example of CALL

      挪用的例子

    mysql> CALL p10() //

    --------

    | s1 * a |

    --------

    | 25 |

    | 25 |

    --------

    2 rows in set (0.00 sec)

    Query OK, 0 rows affected (0.00 sec)
      成效显现了历程能正常事情

      (5) Scope

      作用域

    CREATE PROCEDURE p11 ()

    BEGIN

    DECLARE x1 CHAR(5) DEFAULT 'outer';

    BEGIN

    DECLARE x1 CHAR(5) DEFAULT 'inner';

    SELECT x1;

    END;

    SELECT x1;

    END; //

      而今我们来评论一下作用域的成绩。例子中有嵌套的BEGIN/END块,当然这是公道的。同时包括两个变量,名字都是x1,这样也是公道的。外部的变量在其作用域内享有更高的优先权。当实验到END语句时,外部变量散失,此时曾经在其作用域外,变量不再可见了,因此在存储历程外再也不能找到这个声了然的变量,可是你可以颠末历程OUT参数也许将其值指派 给会话变量来保留其值。

      挪用作用域例子的历程:

    mysql> CALL p11()//

    -------

    | x1 |

    -------

    | inner |

    -------

    -------

    | x1 |

    -------

    | outer |

    -------
      我们看到的成效时第一个SELECT语句检索到最内层的变量,第二个检索到第二层的变量

    Conditions and IF-THEN-ELSE 前提式和IF-THEN-ELSE

      1.

      而今我们可以写一些包括前提式的例子:

    CREATE PROCEDURE p12 (IN parameter1 INT)

    BEGIN

    DECLARE variable1 INT;

    SET variable1 = parameter1 1;

    IF variable1 = 0 THEN

    INSERT INTO t VALUES (17);

    END IF;

    IF parameter1 = 0 THEN

    UPDATE t SET s1 = s1 1;

    ELSE

    UPDATE t SET s1 = s1 2;

    END IF;

    END; //
      这里是一个包括IF语句的历程。外面有两个IF语句,一个是IF语句END IF,另一个是IF语句ELSE语句END IF。我们可以在这里运用复杂的历程,但我会虽然使其复杂让你能更容易弄分明。

      2.

    CALL p12 (0) //
      我们挪用这个历程,传入值为0,这样parameter1的值将为0。

      3.

    CREATE PROCEDURE p12 (IN parameter1 INT)

    BEGIN

    DECLARE variable1 INT;

    SET variable1 = parameter1 1; <--

    IF variable1 = 0 THEN

    INSERT INTO t VALUES (17);

    END IF;

    IF parameter1 = 0 THEN

    UPDATE t SET s1 = s1 1;

    ELSE

    UPDATE t SET s1 = s1 2;

    END IF;

    END; //
      这里变量variable1被赋值为parameter1加1的值,以是实验后变量variable1为1。

      4.

    CREATE PROCEDURE p12 (IN parameter1 INT)

    BEGIN

    DECLARE variable1 INT;

    SET variable1 = parameter1 1;

    IF variable1 = 0 THEN <--

    INSERT INTO t VALUES (17);

    END IF;

    IF parameter1 = 0 THEN

    UPDATE t SET s1 = s1 1;

    ELSE

    UPDATE t SET s1 = s1 2;

    END IF;

    END; //

      因为变量variable1值为1,因此前提"if variable1 = 0"为假,

    IF

    ……

    END IF
      被跳过,没有被实验。

      5.

    CREATE PROCEDURE p12 (IN parameter1 INT)

    BEGIN

    DECLARE variable1 INT;

    SET variable1 = parameter1 1;

    IF variable1 = 0 THEN

    INSERT INTO t VALUES (17);

    END IF;

    IF parameter1 = 0 THEN <--

    UPDATE t SET s1 = s1 1;

    ELSE

    UPDATE t SET s1 = s1 2;

    END IF;

    END; //
      到第二个IF前提,鉴别成效为真,于是中间语句被实验了

      6.

    CREATE PROCEDURE p12 (IN parameter1 INT)

    BEGIN

    DECLARE variable1 INT;

    SET variable1 = parameter1 1;

    IF variable1 = 0 THEN

    INSERT INTO t VALUES (17);

    END IF;

    IF parameter1 = 0 THEN

    UPDATE t SET s1 = s1 1; <--

    ELSE

    UPDATE t SET s1 = s1 2;

    END IF;

    END; //

      因为参数parameter1值即是0,UPDATE语句被实验。如果parameter1值为NULL,则下一条UPDATE语句将被实验而今表t中有两行,他们都包括值5,以是如果我们挪用p12,两行的值会酿成6。

      7.

    mysql> CALL p12(0)//

    Query OK, 2 rows affected (0.28 sec)

    mysql> SELECT * FROM t//

    ------

    | s1 |

    ------

    | 6 |

    | 6 |

    ------

    2 rows in set (0.01 sec)
      成效也是我们所盼愿的那样。

    CASE 指令

      1.

    CREATE PROCEDURE p13 (IN parameter1 INT)

    BEGIN

    DECLARE variable1 INT;

    SET variable1 = parameter1 1;

    CASE variable1

    WHEN 0 THEN INSERT INTO t VALUES (17);

    WHEN 1 THEN INSERT INTO t VALUES (18);

    ELSE INSERT INTO t VALUES (19);

    END CASE;

    END; //
      如果需求进行更多前提真假的鉴别我们可以运用CASE语句。CASE语句运用和IF一样复杂。

      我们可以参考下面的例子:

      2.

    mysql> CALL p13(1)//

    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT * FROM t//

    ------

    | s1 |

    ------

    | 6 |

    | 6 |

    | 19 |

    ------

    3 rows in set (0.00 sec)
      实验历程后,传入值1,如下面例子,值19被拔出到表t中。

      Question

      成绩

      成绩: CALL p13(NULL) //的作用是什么?

      另一个:这个CALL语句做了那些举动?

      你可以颠末历程实验后察看SELECT做了什么,也可以按照代码鉴别,在5秒内做出。

      Answer

      谜底

    mysql> CALL p13(NULL)//

    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT * FROM t//

    ------

    | s1 |

    ------

    | 6 |

    | 6 |

    | 19 |

    | 19 |

    ------

    4 rows in set (0.00 sec)
      谜底是当你挪用p13时,MySQL拔出了另一条包括数值19的记实。缘故原由是变量variable1的值为NULL,CASE语句的ELSE部门就被实验了。盼愿这对大师有意义。如果你答复不出来,没有成绩,我们可以接管向下走。

    Loops 轮回语句


    WHILE ... END WHILE

    LOOP ... END LOOP

    REPEAT ... END REPEAT

    GOTO
      下面我们将会创设一些轮回。我们有三种规范楷模的轮回体例:

      WHILE轮回,LOOP轮回以及REPEAT轮回。另有一种非规范楷模的轮回体例:GO TO(译者语:最好不要用吧,用了就使流程混乱)。

    WHILE ... END WHILE

    CREATE PROCEDURE p14 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    WHILE v < 5 DO

    INSERT INTO t VALUES (v);

    SET v = v 1;

    END WHILE;

    END; //
      这是WHILE轮回的体例。我很爱好这种体例,它跟IF语句相同,因此不需求掌握许多新的语法。这里的INSERT和SET语句在WHILE和END WHILE之间,当变量v大于5的时分轮回将会加入。运用

    "SET v = 0;"
      语句使为了防备一个罕见的错误,如果没有初始化,默许变量值为NULL,而NULL和任何值操纵成效都为NULL。

    WHILE ... END WHILE example

    mysql> CALL p14()//

    Query OK, 1 row affected (0.00 sec)

      以上便是挪用历程p14的成效不用存眷体系前去是"one row affected"照样"five rows affected",因为这里的计数只对着末一个INSERT举动进行计数。

    WHILE ... END WHILE example: CALL

    mysql> select * from t; //

    ------

    | s1 |

    ------

    ....

    | 0 |

    | 1 |

    | 2 |

    | 3 |

    | 4 |

    ------

    9 rows in set (0.00 sec)
      挪用后可以看到顺序向数据库中拔出了5行。

    REPEAT ... END REPEAT

    CREATE PROCEDURE p15 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    REPEAT

    INSERT INTO t VALUES (v);

    SET v = v 1;

    UNTIL v >= 5

    END REPEAT;

    END; //

      这是一个REPEAT轮回的例子,服从和后面WHILE轮回一样。区别在于它在实验后检查成效,而WHILE则是实验前检查。(译者语:也许同即是DO WHILE吧)

    REPEAT ... END REPEAT: look at the UNTIL: UNTIL的作用

    CREATE PROCEDURE p15 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    REPEAT

    INSERT INTO t VALUES (v);

    SET v = v 1;

    UNTIL v >= 5 <--

    END REPEAT;

    END; //
      寄望到UNTIL语句后面没有分号,在这里可以不写分号,当然你加上额定的分号更好。

      REPEAT ... END REPEAT: calling :挪用

    mysql> CALL p15()//

    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT COUNT(*) FROM t//

    ----------

    | COUNT(*) |

    ----------

    | 14 |

    ----------

    1 row in set (0.00 sec)
      我们可以看到挪用p15历程后又拔出了5行记实

    LOOP ... END LOOP

    CREATE PROCEDURE p16 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //
      以上是LOOP轮回的例子。

      LOOP轮回不需求初始前提,这点和WHILE轮回相同,同时它又和REPEAT轮回一样也不需求竣事前提。


      LOOP ... END LOOP: with IF and LEAVE 包括IF和LEAVE的LOOP轮回

    CREATE PROCEDURE p16 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN <--

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //
      在轮回外部加入IF语句,在IF语句中包括LEAVE语句。这里LEAVE语句的意义是离开轮回。

      LEAVE的语法是LEAVE加轮回语句标号,关于轮回语句的标号成绩我会在后面进一步讲解。
      LOOP ... END LOOP: calling :挪用

    mysql> CALL p16()//

    Query OK, 1 row affected (0.00 sec)

    mysql> SELECT COUNT(*) FROM t//

    ----------

    | COUNT(*) |

    ----------

    | 19 |

    ----------

    1 row in set (0.00 sec)
      挪用历程p16后,成效是另5行被拔出表t中。

    Labels 标号


    CREATE PROCEDURE p17 ()

    label_1: BEGIN

    label_2: WHILE 0 = 1 DO LEAVE label_2; END

    WHILE;

    label_3: REPEAT LEAVE label_3; UNTIL 0 =0

    END REPEAT;

    label_4: LOOP LEAVE label_4; END LOOP;

    END; //
      着末一个轮回例子中我运用了语句标号。而今这里有一个包括4个语句标号的历程的例子。我们可以在BEGIN、WHILE、REPEAT也许LOOP语句前运用语句标号,语句标号只能在公道的语句后面运用。因此"LEAVE label_3"意味着离开语句标号名定义为label_3的语句或复合语句。

    End Labels 标号竣事符

    CREATE PROCEDURE p18 ()

    label_1: BEGIN

    label_2: WHILE 0 = 1 DO LEAVE label_2; END

    WHILE label_2;

    label_3: REPEAT LEAVE label_3; UNTIL 0 =0

    END REPEAT label_3 ;

    label_4: LOOP LEAVE label_4; END LOOP

    label_4 ;

    END label_1 ; //
      你也可以在语句竣事时运用语句标号,和在收尾时运用一样。这些标号竣事符并不是十分有效。

      它们是可选的。如果你需求,他们必须和开始定义的标号名字一样当然为了有良好的编程风气,随意对付他人阅读,最好照样运用标号竣事符。

    LEAVE and Labels 跳出和标号


    CREATE PROCEDURE p19 (parameter1 CHAR)

    label_1: BEGIN

    label_2: BEGIN

    label_3: BEGIN

    IF parameter1 IS NOT NULL THEN

    IF parameter1 = 'a' THEN

    LEAVE label_1;

    ELSE BEGIN

    IF parameter1 = 'b' THEN

    LEAVE label_2;

    ELSE

    LEAVE label_3;

    END IF;

    END;

    END IF;

    END IF;

    END;

    END;

    END;//

    LEAVE
      语句使顺序跳出复杂的复合语句。

    ITERATE

      迭代如果目的是ITERATE(迭代)语句的话,就必须用到LEAVE语句

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    IF v = 3 THEN

    SET v = v 1;

    ITERATE loop_label;

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //

    ITERATE

      (迭代)语句和LEAVE语句一样也是在轮回外部的轮回引用,它有点像C言语中的“Continue”,异样它可以出而今复合语句中,引用复合语句标号,ITERATE(迭代)意思是从头开始复合语句。

      那我们启动并察看下面这个轮回,这是个需求迭代历程的轮回:

    ITERATE: Walking through the loop

    深化轮回

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP <--

    IF v = 3 THEN

    SET v = v 1;

    ITERATE loop_label;

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //
      让这个曾经定义了标号的轮回运转起来。

    ITERATE: Walking through the loop

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    IF v = 3 THEN <--

    SET v = v 1;

    ITERATE loop_label;

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //

      v的值酿成3,然后我们把它增加到4。

    ITERATE: walking through the loop

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    IF v = 3 THEN

    SET v = v 1;

    ITERATE loop_label; <--

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //
      然后开始ITERATE(迭代)历程。

    ITERATE: walking through the loop

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP <--

    IF v = 3 THEN

    SET v = v 1;

    ITERATE loop_label;

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; //

      这里的ITERATE(迭代)让轮回又回到了轮回的头部。

    ITERATE: walking through the loop

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    IF v = 3 THEN

    SET v = v 1;

    ITERATE loop_label;

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label; <--

    END IF;

    END LOOP;

    END; //
      当v的值变为5时,顺序将实验LEAVE语句

    ITERATE: walking through the loop

    CREATE PROCEDURE p20 ()

    BEGIN

    DECLARE v INT;

    SET v = 0;

    loop_label: LOOP

    IF v = 3 THEN

    SET v = v 1;

    ITERATE loop_label;

    END IF;

    INSERT INTO t VALUES (v);

    SET v = v 1;

    IF v >= 5 THEN

    LEAVE loop_label;

    END IF;

    END LOOP;

    END; // <--
      LEAVE的成效便是跳出轮回,使运转指令抵达复合语句的着末一步。

    GOTO

    CREATE PROCEDURE p...

    BEGIN

    ...

    LABEL label_name;

    ...

    GOTO label_name;

    ...

    END;
      MySQL的存储历程中可以运用GOTO语句。虽然这不是规范楷模SQL语句,并且在这里设立培育提升标号的方式也和常规中的纷比方样。因为为了和其他DBMS兼容,这个语句会慢被削减,以是我们在MySQL参考手册中没有提及。

    Grand combination

    大组合

    CREATE PROCEDURE p21

    (IN parameter_1 INT, OUT parameter_2 INT)

    LANGUAGE SQL DETERMINISTIC SQL SECURITY INVOKER

    BEGIN

    DECLARE v INT;

    label goto_label; start_label: LOOP

    IF v = v THEN LEAVE start_label;

    ELSE ITERATE start_label;

    END IF;

    END LOOP start_label;

    REPEAT

    WHILE 1 = 0 DO BEGIN END;

    END WHILE;

    UNTIL v = v END REPEAT;

    GOTO goto_label;

    END;//
      下面例子中的语句包括了我们之前讲的通通语法,包孕参数列表,特性参数,BEGIN/END块复合语句,变量声明,IF,WHILE,LOOP,REPEAT,LEAVE,ITERATE,GOTO。这是一个荒谬的存储历程,我不会运转它,因为外面有无尽的轮回。可是外面的语法却十分公道。这些是新的流程控制和变量声明语句。下面我们将要兵戈更多新的东西。




    版权声明: 原创作品,许愿转载,转载时请务必以超链接方式标明文章 原始来因 、作者信息和本声明。不然将穷究法则责任。

  • 相关阅读:
    各种alloc傻傻分不清楚
    嵌入式开发一般流程
    谈谈看门狗在嵌入式中的用法
    基于开发板的二次嵌入式开发
    谈一谈接口电路
    学习ucos和ARM体系结构的路线图
    寻找链表的中位节点(利用快慢指针)
    水箱容积问题
    盛水最多的容器
    数据结构与算法分析C语言描述第二版第79页
  • 原文地址:https://www.cnblogs.com/zgqjymx/p/1975799.html
Copyright © 2011-2022 走看看