来源:网海拾贝
作者: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。这是一个荒谬的存储历程,我不会运转它,因为外面有无尽的轮回。可是外面的语法却十分公道。这些是新的流程控制和变量声明语句。下面我们将要兵戈更多新的东西。
版权声明:
原创作品,许愿转载,转载时请务必以超链接方式标明文章 原始来因 、作者信息和本声明。不然将穷究法则责任。