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/p/1975799.html