在MariaDB 10.1.1+版本中,我们可以在存储过程以外来使用复合语句了,顾名思义,复合语句就是将多条语句作为一个整体来执行,可以在其中使用一些逻辑判断,循环等功能,大大提高了SQL语言的可编程性。
在存储过程以外使用复合语句需要遵守以下约定:
- 仅可使用BEGIN, IF, CASE, LOOP, WHILE, REPEAT语句
- BEGIN必须使用BEGIN NOT ATOMIC,这样不会规避autocommit
- 不能以标签开头
当要使用复合语句时,可以使用如下的格式来使用:
BEGIN [NOT ATOMIC] [statement_list] END
因为SQL语句要使用;来作为结束的标识符,但是,多条SQL语句,到底哪个才是结束符了?所以我们可以将复合语句的结束符修改为其他字符,使用如下命令即可:|可以替换为任意数量的任意字符。
delimiter | //该命令在当前会话有效,会影响后续所有SQL语句的结束符
MariaDB [world]> DELIMITER || MariaDB [world]> BEGIN NOT ATOMIC -> SELECT * FROM user; -> SELECT * FROM department; -> END -> ||
会顺序显示两张表的内容,但是,有什么呢?
嘿,都说了,增加了可编程性,还没判断、循环呢。
本地变量仅在当前BEGIN..END内生效,定义一个本地变量的语法如下:
DECLARE var_name [, var_name] type [DEFAULT value] type就是MariaDB中支持的那些数据类型。
比如如下例子:查询test1用户的组ID并放入到tmpdid变量中去
MariaDB [world]> BEGIN NOT ATOMIC -> DECLARE tmpdid INT DEFAULT 0; -> SELECT deptid INTO tmpdid FROM user WHERE name='test1'; -> SELECT tmpdid; -> END| +--------+ | tmpdid | +--------+ | 1 | +--------+ 1 row in set (0.00 sec)
所以说,BEGIN…END是可以嵌套使用的,如在IF语句中使用BEGIN…END来创建一个新的定义域,当然BEGIN…END也是开启事务的标志
语法如下:
IF search_condition THEN statement_list [ELSEIF search_condition THEN statement_list] ... [ELSE statement_list] END IF
这个就跟编程语言中的一样了,不再絮叨,来试试吧。
BEGIN NOT ATOMIC DECLARE tmpdid INT DEFAULT 0; SELECT deptid INTO tmpdid FROM user WHERE name='test1'; IF (tmpdid = 1) THEN SELECT 'The User test1 is the member of salse'; ELSE SELECT * FROM department WHERE id = tmpdid; END IF; END|
所以search_condition只要是可以表达TRUE或FALSE的表达式都行,比如:
BEGIN NOT ATOMIC IF EXISTS(SELECT * FROM user WHERE name = 'lucy') THEN SELECT 'Find the user lucy'; ELSE SELECT 'Not Find'; END IF; END| +--------------------+ | Find the user lucy | +--------------------+ | Find the user lucy | +--------------------+ 1 row in set (0.00 sec)
CASE有两种用法,一种是像编程语言中的SWITCH一样,进行数据的挑选,另一种则是实现了多分支的IF-ELSE语句,语法如下:
//对某一个值进行筛选 CASE case_value WHEN when_value THEN statement_list [WHEN when_value THEN statement_list] ... [ELSE statement_list] END CASE //多分支的IF-ELSE CASE WHEN search_condition THEN statement_list [WHEN search_condition THEN statement_list] ... [ELSE statement_list] END CASE
…想不出来例子,放弃,哪天想到了再来补吧。
附官方例子一枚:
DELIMITER | CREATE PROCEDURE p() BEGIN DECLARE v INT DEFAULT 1; CASE v WHEN 2 THEN SELECT v; WHEN 3 THEN SELECT 0; ELSE BEGIN END; END CASE; END; |
LOOP之前没有用过,好像很多编程语言里都没有LOOP这个关键字了,用来实现简单的循环,需要配合LEAVE语句跳出循环。
设置一变量,将其加到100并退出:为啥要加到100?鬼知道,哈哈哈。
BEGIN NOT ATOMIC DECLARE tempNum INT DEFAULT 0; test:LOOP SET tempNum=tempNum+1; IF tempNum=100 THEN LEAVE test; END IF; END LOOP test; SELECT tempNum; END; |
所以LOOP的语法如下:
[begin_label:] LOOP statement_list END LOOP [end_label]
通常,需要设置一个begin_label,用于标识该循环,以方便使用LEAVE跳出该循环,而end_label可以省略,但是如果想要给end_label的话,必须与begin_label的名称相同,而LEAVE的语法就很简单了:
LEAVE label
WHILE就与编程语言中的一样了,语法如下:
[begin_label:] WHILE search_condition DO statement_list END WHILE [end_label]
当search_condition表达式不为TRUE时则不再执行循环。
查找某一用户的ID值为多少,为什么要写个循环呢?不知道呀,用WHERE不更好吗?
REPEAT循环看起来非常像do…while循环,好吧,其实就是一回事。
第一次循环体不判断任何条件执行一次,然后再判断条件,如果条件还满足则继续执行,直到条件不满足为之,语法如下:
[begin_label:] REPEAT statement_list UNTIL search_condition END REPEAT [end_label]
拼接所有用户名为一个字符串:
MariaDB [world]> BEGIN NOT ATOMIC -> DECLARE i INT DEFAULT 1; -> DECLARE userNames VARCHAR(200) DEFAULT ''; -> DECLARE tmpName VARCHAR(10) DEFAULT ''; -> DECLARE userNums INT DEFAULT 0; -> SELECT COUNT(id) INTO userNums FROM user; -> REPEAT -> SELECT name INTO tmpName FROM user WHERE id = i; -> SET userNames = CONCAT(userNames,',',tmpName); -> SET i = i +1; -> UNTIL NOT i< =userNums -> END REPEAT; -> SELECT userNames; -> END| +--------------------------------------------------------------------------------------------+ | userNames | +--------------------------------------------------------------------------------------------+ | ,test,test1,lucy,mars,mark,test6,test7,test7,test8,test8,test9,test10,test11,test12,test13 | +--------------------------------------------------------------------------------------------+
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/120120.html