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




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

转载于:https://www.cnblogs.com/zgqjymx/archive/2011/03/07/1975700.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值