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。这是一个荒谬的存储历程,我不会运转它,因为里面有无尽的循环。但是里面的语法却很是正当。这些是新的流程控制和变量声明语句。上面我们将要干戈更多新的工具。




    版权声明: 原创作品,承诺转载,转载时请务必以超链接体式款式标明文章 原始出处 、作者信息和本声明。否则将穷究法律责任。

  • 相关阅读:
    HTTP协议概述
    Linux grep
    用bindService()启动Service的方式与生命周期
    关于服务Service使用startService()函数启动时的生命周期
    sendStickyBroadCast函数的使用
    让Eclipse全屏的插件
    多个BroadCastReceiver同时匹配同一类Intent发送的消息的情况
    JFileChooser的使用心得(FileFilter)
    php mysql实现无限级分类 | 树型显示分类关系
    关于php扩展编程如何返回数组的问题
  • 原文地址:https://www.cnblogs.com/zgqjymx/p/1975700.html
Copyright © 2011-2022 走看看