五、MYSQL存儲過程和函數(shù)

Create procedure/function語句

? create procedure用來創(chuàng)建存儲過程螺捐,create function用來創(chuàng)建函數(shù)


? 函數(shù)與存儲過程最大的區(qū)別就是函數(shù)調(diào)用有返回值颠悬,調(diào)用存儲過程用call語句,而調(diào)用函數(shù)就直接引用函數(shù)名+參數(shù)即可
? Definer和sql security子句指定安全環(huán)境
? Definder是MySQL的特殊的訪問控制手段定血,當(dāng)數(shù)據(jù)庫當(dāng)前沒有這個用戶權(quán)限時赔癌,執(zhí)行存儲過程可能會報錯
? sql secuirty的值決定了調(diào)用存儲過程的方式,取值 :definer(默認(rèn))或者invoker definer:在執(zhí)行存儲過程前驗證definer對應(yīng)的用戶如:cdq@127.0.0.1是否存在澜沟,以及是否具有執(zhí)行存儲過程的權(quán)限灾票,若沒有則報錯 invoker:在執(zhí)行存儲過程時判斷inovker即調(diào)用該存儲過程的用戶是否有相應(yīng)權(quán)限,若沒有則報錯
? IN,OUT,INOUT三個參數(shù)前的關(guān)鍵詞只適用于存儲過程倔喂,對函數(shù)而言所有的參數(shù)默認(rèn)都是輸入?yún)?shù)
? IN輸入?yún)?shù)用于把數(shù)值傳入到存儲過程中铝条;OUT輸出參數(shù)將數(shù)值傳遞到調(diào)用者,初始值是NULL席噩;INOUT輸入輸出參數(shù)把數(shù)據(jù)傳入到存儲過程,在存儲過程中修改之后再傳遞到調(diào)用者

 mysql> delimiter //
 mysql> CREATE PROCEDURE simpleproc (IN param1 int,OUT param2 INT)
 -> BEGIN
 -> SELECT COUNT(*) INTO param2 FROM students where sid>param1;
 -> END//
 Query OK, 0 rows affected (0.03 sec)
 Delimiter ;
 mysql> CALL simpleproc(1, @a);
 Query OK, 0 rows affected (0.00 sec)
 mysql> SELECT @a;
 +------+
 | @a |
 +------+
 | 2 |
 +------+
 1 row in set (0.00 sec)

? Delimiter命令是改變語句的結(jié)束符贤壁,MySQL默認(rèn)的結(jié)束符為;號悼枢,由于procedure和function中的;號并不代表創(chuàng)建的結(jié)束,所以要替換成另外的結(jié)束符以便表示創(chuàng)建的結(jié)束
? rontine_body子句可以包含一個簡單的SQL語句脾拆,也可以包含多個SQL語句馒索,通過begin…end將這多個SQL語句包含在一起
? MySQL存儲過程和函數(shù)中也可以包含類似create和drop等DDL語句
? comment子句用來寫入對存儲過程和函數(shù)的注釋
? Language子句用來表示此存儲過程和函數(shù)的創(chuàng)建語言
? 存儲過程和函數(shù)被標(biāo)注為deterministic表明當(dāng)輸入相同的參數(shù)是會返回相同的結(jié)果,反之如果是not deterministic則表示相同參數(shù)不會是相同結(jié)果名船,默認(rèn)是not deterministic

 mysql> delimiter //
 mysql> create function simplefunc(param1 int)
 -> returns int
 -> begin
 -> update students set sex=1 where sid=param1;
 -> select count(*) into @a from students where sid>param1;
 -> return @a;
 -> end;
 -> //
 Query OK, 0 rows affected (0.00 sec)
 mysql> delimiter ;
 mysql> select simplefunc(1);
 +---------------+
 | simplefunc(1) |
 +---------------+
 | 2             |
+----------------+
 mysql> select * from students where sid=1;
 +------+-------+------+
 | sid | sname  | sex  |
 +------+-------+------+
 | 1   | a      | 1    | 
 +------+-------+------+


[root@localhost ~]# mysql -u cdq –p
delimiter //
CREATE PROCEDURE simpleproc (IN param1 int,OUT param2 INT)
BEGIN
SELECT COUNT(*) INTO param2 FROM students where sid>param1;
END//
delimiter ;


[root@localhost ~]# mysql -u root –p
mysql> call simpleproc(1,@a);
mysql> drop user cdq@localhost;
mysql> call simpleproc(1,@a);
ERROR 1449 (HY000): The user specified as a definer ('cdq'@'localhost') does not exist
mysql> alter procedure simpleproc sql security invoker;
mysql> call simpleproc(1,@a);

? 相關(guān)屬性短語只有咨詢含義绰上,并不是強(qiáng)制性的約束

? Contains sql表明此存儲過程或函數(shù)不包含讀或者寫數(shù)據(jù)的語句,這是默認(rèn)屬性
? NO SQL表示此存儲過程或函數(shù)不包含SQL語句
? Reads sql data表示此存儲過程包含諸如select的查詢數(shù)據(jù)的語句渠驼,但不包含插入或刪除數(shù)據(jù)的語句
? Modifies sql data表示此存儲過程包含插入或刪除數(shù)據(jù)的語句

drop procedure/function語句

? Drop procedure/function語句用來刪除指定名稱的存儲過程或函數(shù)


? If exists關(guān)鍵詞用來避免在刪除一個本身不存在的存儲過程或函數(shù)時蜈块,MySQL返回錯誤

 mysql> drop procedure simpleproc;
 Query OK, 0 rows affected (0.00 sec)
 mysql> drop procedure simpleproc;
 ERROR 1305 (42000): PROCEDURE part2_cn.simpleproc does not exist
 mysql> drop function if exists simplefunc;
 Query OK, 0 rows affected, 1 warning (0.01 sec)

Begin…end復(fù)合語句

? Begin…end語句通常出現(xiàn)在存儲過程、函數(shù)和觸發(fā)器中,其中可以包含一個或多個語句百揭,每個語句用;號隔開

標(biāo)簽語句

? 標(biāo)簽label可以加在begin…end語句以及l(fā)oop, repeat和while語句
? 語句中通過iterate和leave來控制流程爽哎,iterate表示返回指定標(biāo)簽位置,leave表示跳出標(biāo)簽

 mysql> delimiter //
 mysql> CREATE PROCEDURE doiterate(IN p1 int, OUT p2 int)
 -> BEGIN
 -> label1: LOOP
 -> SET p1 = p1 + 1;
 -> IF p1 < 10 THEN ITERATE label1; END IF;
 -> LEAVE label1;
 -> END LOOP label1;
 -> set p2=p1;
 -> END;
 -> //
 Query OK, 0 rows affected (0.00 sec)
 mysql> delimiter ;
 mysql> call doiterate(1,@a);
 Query OK, 0 rows affected (0.00 sec)
 mysql> select @a;
 +------+
 | @a |
 +------+
 | 10 |
 mysql> call doiterate(5,@a);
 Query OK, 0 rows affected (0.00 sec)
 mysql> select @a;
 +------+
 | @a |
 +------+
 | 10 | 
 +------+

Declare語句

? Declare語句通常用來聲明本地變量器一、游標(biāo)课锌、條件或者h(yuǎn)andler
? Declare語句只允許出現(xiàn)在begin … end語句中而且必須出現(xiàn)在第一行
? Declare的順序也有要求,通常是先聲明本地變量祈秕,再是游標(biāo)渺贤,然后是條件和handler

存儲過程中的變量

? 本地變量可以通過declare語句進(jìn)行聲明
? 聲明后的變量可以通過select … into var_list進(jìn)行賦值,或者通過set語句賦值请毛,或者通過定義游標(biāo)并使用fetch … into var_list賦值
? 通過declare聲明變量方法:

? 使用default指定變量的默認(rèn)值志鞍,如果沒有指定默認(rèn)值則初始值為NULL
? Type指明該變量的數(shù)據(jù)類型
? 聲明的變量作用范圍為被聲明的begin … end語句塊之間
? 聲明的變量和被引用的數(shù)據(jù)表中的字段名要區(qū)分開來

 delimiter //
 CREATE PROCEDURE sp1 (v_sid int)
 BEGIN
 DECLARE xname VARCHAR(5) DEFAULT 'bob';
 DECLARE xsex INT;
 SELECT sname, sex INTO xname, xsex
 FROM students WHERE sid= v_sid;
 SELECT xname,xsex;
 END;
 //
 delimiter ;

 mysql> call sp1(1);
 +-------+------+
 | xname | xsex |
 +-------+------+
 | a     | 1    |
 +-------+------+

流程控制語句

? MySQL支持if,case,iterate,leave,loop,while,repeat語句作為存儲過程和函數(shù)中的流程控制語句,另外return語句也是函數(shù)中的特定流程控制語句

流程控制case語句

? Case語句在存儲過程或函數(shù)中表明了復(fù)雜的條件選擇語句



? 第一個語句中case_value與后面各句的when_value依次做相等的對比获印,如果碰到相等的述雾,則執(zhí)行對應(yīng)的后面的statement_list,否則接著對比兼丰,如果都沒有匹配玻孟,則執(zhí)行else后面的statement_list
? 第二個語句中當(dāng)search_condition滿足true/1的結(jié)果時,則執(zhí)行對應(yīng)的statement_list鳍征,否則執(zhí)行else對應(yīng)的statement_list
? Statement_list可以包含一個或多個SQL語句

 delimiter //
 CREATE PROCEDURE exp_case(v_sid int)
 BEGIN
 DECLARE v INT DEFAULT 1;
 select sex into v from students where sid=v_sid;
 CASE v
 WHEN 0 THEN update students set sex=1 where sid=v_sid;
 WHEN 1 THEN update students set sex=0 where sid=v_sid;
 ELSE
 update students set sex=-1 where sid=v_sid;
 END CASE;
 END;
 //
 delimiter ;

 mysql> call exp_case(1);
 Query OK, 1 row affected (0.01 sec) 

 delimiter //
 CREATE PROCEDURE exp_case2(v_sid int)
 BEGIN
 DECLARE v INT DEFAULT 1;
 select sex into v from students where sid=v_sid;
 CASE
 WHEN v=0 THEN update students set sex=1 where sid=v_sid;
 WHEN v=1 THEN update students set sex=0 where sid=v_sid;
 ELSE
 update students set sex=-1 where sid=v_sid;
 END CASE;
 END;
 //
 delimiter ;

 mysql> call exp_case2(1);
 Query OK, 1 row affected (0.01 sec)

流程控制IF語句

? IF語句在存儲過程或函數(shù)中表明了基礎(chǔ)的條件選擇語句


? IF語句中如果search_condition滿足true/1的條件黍翎,則執(zhí)行對應(yīng)的statement_list,否則再判斷elseif中的search_condition是否滿足true/1的條件艳丛,如果都不滿足則執(zhí)行else中的statement_list語句
? Statement_list中可以包含一個或多個SQL語句

 DELIMITER //
 CREATE FUNCTION SimpleCompare(n INT, m INT)
 RETURNS VARCHAR(20)
 BEGIN
 DECLARE s VARCHAR(20);
 IF n > m THEN SET s = '>';
 ELSEIF n = m THEN SET s = '=';
 ELSE SET s = '<';
 END IF;
 SET s = CONCAT(n, ' ', s, ' ', m);
 RETURN s;
 END //
 DELIMITER ;

 mysql> select simplecompare(1,2);
 +--------------------+
 | simplecompare(1,2) |
 +--------------------+
 | 1 < 2              |
 +--------------------+
 1 row in set (0.02 sec)

 DELIMITER //
 CREATE FUNCTION VerboseCompare (n INT, m INT) ##嵌套if語句
 RETURNS VARCHAR(50)
 BEGIN
 DECLARE s VARCHAR(50);
 IF n = m THEN SET s = 'equals';
 ELSE
  IF n > m THEN SET s = 'greater';
  ELSE SET s = 'less';
  END IF;
 SET s = CONCAT('is ', s, ' than');
 END IF;
 SET s = CONCAT(n, ' ', s, ' ', m, '.');
 RETURN s;
 END //
 DELIMITER ;

 mysql> select verbosecompare(1,2);
 +---------------------+
 | verbosecompare(1,2) |
 +---------------------+
 | 1 is less than 2.   | 
 +---------------------+
 1 row in set (0.02 sec)

注:
如果報錯:ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
翻譯:這個函數(shù)沒有確定性匣掸,沒有SQL,或者在聲明中讀取SQL數(shù)據(jù)氮双,并且啟用了二進(jìn)制日志記錄(您可能想要使用不太安全的log bin trust函數(shù)creator變量)
這是我們開啟了 bin-log, 我們就必須指定我們的函數(shù)是否是
1 DETERMINISTIC 不確定的
2 NO SQL 沒有SQl語句碰酝,當(dāng)然也不會修改數(shù)據(jù)
3 READS SQL DATA 只是讀取數(shù)據(jù),當(dāng)然也不會修改數(shù)據(jù)
4 MODIFIES SQL DATA 要修改數(shù)據(jù)
5 CONTAINS SQL 包含了SQL語句

其中在 function 里面戴差,只有 DETERMINISTIC, NO SQL 和 READS SQL DATA 被支持送爸。如果我們開啟了 bin-log, 我們就必須為我們的 function 指定一個參數(shù)。
在 MySQL 中創(chuàng)建函數(shù)時出現(xiàn)這種錯誤的解決方法:
set global log_bin_trust_function_creators=TRUE;

流程控制iterate語句

? Iterate語句僅出現(xiàn)在loop,repeat,while循環(huán)語句中暖释,其含義表示重新開始此循環(huán)


? Label表示自定義的標(biāo)簽名

流程控制leave語句

? Leave語句表明退出指定標(biāo)簽的流程控制語句塊
? 通常會用在begin…end袭厂,以及l(fā)oop,repeat,while的循環(huán)語句中


? Label表明要退出的標(biāo)簽名

流程控制iterate和leave語句

 mysql> delimiter //
 mysql> CREATE PROCEDURE doiterate(IN p1 INT, OUT p2 int)
 -> BEGIN
 -> label1: LOOP
 -> SET p1 = p1 + 1;
 -> IF p1 < 10 THEN ITERATE label1; END IF;
 -> LEAVE label1;
 -> END LOOP label1;
 -> set p2=p1;
 -> END;
 -> //
 Query OK, 0 rows affected (0.00 sec)
 mysql> delimiter ;

流程控制loop語句

? Loop語句是存儲過程或函數(shù)中表達(dá)循環(huán)執(zhí)行的一種方式


? 其中的statement_list可以包含一個或多個SQL語句

CREATE PROCEDURE doiterate(p1 INT)
BEGIN
 label1: LOOP
 SET p1 = p1 + 1;
 IF p1 < 10 THEN
 ITERATE label1;
 END IF;
 LEAVE label1;
 END LOOP label1;
 SET @x = p1;
END;

流程控制repeat語句

? repeat語句是存儲過程或函數(shù)中表達(dá)循環(huán)執(zhí)行的一種方式


? Repeat語句中statement_list一直重復(fù)執(zhí)行直到search_condition條件滿足
? Statement_list可以包含一個或多個SQL語句

 mysql> delimiter //
 mysql> CREATE PROCEDURE dorepeat(p1 INT)
 -> BEGIN
 -> SET @x = 0;
 -> REPEAT
 -> SET @x = @x + 1;
 -> UNTIL @x > p1 END REPEAT;
 -> END
 -> //
 Query OK, 0 rows affected (0.00 sec)
 mysql> delimiter ;
 mysql> CALL dorepeat(1000)//
 Query OK, 0 rows affected (0.00 sec)
 mysql> SELECT @x//
 +------+
 | @x   |
 +------+
 | 1001 |
 +------+
 1 row in set (0.00 sec)

流程控制while語句

? while語句是存儲過程或函數(shù)中表達(dá)循環(huán)執(zhí)行的一種方式


? 當(dāng)search_condition返回為true時,則循環(huán)執(zhí)行statement_list中的語句球匕,直到search_condition的結(jié)果返回為false
? Statement_list中可以包含一個或多個SQL語句

 DELIMITER //
 CREATE PROCEDURE dowhile()
 BEGIN
 DECLARE v1 INT DEFAULT 5;
 WHILE v1 > 0 DO
 update students set sex=-1 where sid=v1;
 SET v1 = v1 - 1;
 END WHILE;
 END;
 //
 DELIMITER ;

 mysql> call dowhile();
 Query OK, 1 row affected (0.00 sec)
 mysql> select * from students;
 +------+-------+------+
 | sid  | sname | sex  |
 +------+-------+------+
 | 1    | a     | -1   |
 | 2    | b     | -1   |
 | 3    | c     | -1   |
 +------+-------+------+

流程控制return語句

? Return語句用在函數(shù)中纹磺,用來終結(jié)函數(shù)的執(zhí)行并將指定值返回給調(diào)用者


? 在函數(shù)中必須要有至少一個return語句,當(dāng)有多個return語句時則表明函數(shù)有多種退出的方式

 delimiter //
 create function doreturn()
 returns int
 begin
 select sex into @a from students where sid=1;
 if @a=1 then return 1;
 elseif @a=0 then return 0;
 else return 999;
 end if;
 end;
 //
 delimiter ;
 mysql> select doreturn();
 +------------+
 | doreturn() |
 +------------+
 | 999 |
 +------------+

cursor游標(biāo)

? Cursor游標(biāo)用來聲明一個數(shù)據(jù)集
? 游標(biāo)的聲明必須在變量和條件聲明之后亮曹,在handler聲明之前

 CREATE PROCEDURE curdemo()
 BEGIN
 DECLARE done INT DEFAULT FALSE;
 DECLARE a CHAR(16);
 DECLARE b, c INT;
 DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
 DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
 OPEN cur1;
 OPEN cur2;
 read_loop: LOOP
 FETCH cur1 INTO a, b;
 FETCH cur2 INTO c;
 IF done THEN
 LEAVE read_loop;
 END IF;
 IF b < c THEN
 INSERT INTO test.t3 VALUES (a,b);
 ELSE
 INSERT INTO test.t3 VALUES (a,c);
 END IF;
 END LOOP;
 CLOSE cur1;
 CLOSE cur2;
 END;

cursor游標(biāo)close語句

? Cursor close語句用來關(guān)閉之前打開的游標(biāo)


? 如果關(guān)閉一個未打開的游標(biāo)橄杨,則MySQL會報錯
? 如果在存儲過程和函數(shù)中未使用此語句關(guān)閉已經(jīng)打開的游標(biāo)秘症,則游標(biāo)會在聲明的begin…end語句塊執(zhí)行完之后自動關(guān)閉

cursor游標(biāo)declare語句

? Cursor declare語句用來聲明一個游標(biāo)和指定游標(biāo)對應(yīng)的數(shù)據(jù)集合,通常數(shù)據(jù)集合是一個select語句


? Select_statement代表一個select語句

cursor游標(biāo)fetch語句

? Cursor fetch語句用來獲取游標(biāo)指定數(shù)據(jù)集的下一行數(shù)據(jù)并將各個字段值賦予后面的變量


? 數(shù)據(jù)集中的字段需要和INTO語句中定義的變量一一對應(yīng)
? 數(shù)據(jù)集中的數(shù)據(jù)都fetch完之后讥珍,則返回NOT FOUND

cursor游標(biāo)open語句

? Open cursor語句用來打開一個之前已經(jīng)聲明好的游標(biāo)

Declare condition語句

? Declare condition語句命名特定的錯誤條件历极,而該特定錯誤可以在declare…h(huán)andler中指定處理方法


? Condition_value指定特定的錯誤條件,可以有以下兩種形式

? Mysql_err_code表示MySQL error code的整數(shù)
? SQLSTATE sqlstate_value表示MySQL中用5位字符串表達(dá)的語句狀態(tài)

? 比如在MySQL中1051error code表示的是unknown table的錯誤衷佃,如果要對這
個錯誤做特殊處理趟卸,可以用三種方法:

 DECLARE CONTINUE HANDLER FOR 1051
 BEGIN
 -- body of handler
 END; 

 DECLARE no_such_table CONDITION FOR 1051;
 DECLARE CONTINUE HANDLER FOR no_such_table
 BEGIN
 -- body of handler
 END;

 DECLARE no_such_table CONDITION FOR SQLSTATE '42S02';
 DECLARE CONTINUE HANDLER FOR no_such_table
 BEGIN
 -- body of handler
 END;

Declare handler語句

? Declare handler語句用來聲明一個handler來處理一個或多個特殊條件,當(dāng)其中的某個條件滿足時則觸發(fā)其中的statement語句執(zhí)行
? Statement可以是一個簡單SQL語句氏义,也可以是begin…end組成的多個語句


? Handler_action子句聲明當(dāng)執(zhí)行完statement語句之后應(yīng)該怎么辦

? Continue代表繼續(xù)執(zhí)行該存儲過程或函數(shù)
? Exit代表退出聲明此handler的begin…end語句塊
? Undo參數(shù)已經(jīng)不支持

Condition_value的值有以下幾種:

? Mysql_err_code表示MySQL error code的整數(shù)
? SQLSTATE sqlstate_value表示MySQL中用5位字符串表達(dá)的語句狀態(tài)
? Condition_name表示之前在declare…condition語句中聲明的名字
? SQLWARNING表示所有的警告信息锄列,即SQLSTATE中01打頭的所有錯誤
? NOT FOUND表示查完或者查不到數(shù)據(jù),即SQLSTATE中02打頭的所有錯誤
? SQLEXCEPTION表示所有的錯誤信息

 DECLARE CONTINUE HANDLER FOR 1051
 BEGIN
 -- body of handler
 END;

 DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
 BEGIN
 -- body of handler
 END;

 DECLARE CONTINUE HANDLER FOR SQLWARNING
 BEGIN
 -- body of handler
 END;

 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
 BEGIN
 -- body of handler
 END;

? 當(dāng)condition發(fā)生但沒有聲明handler時惯悠,則存儲過程和函數(shù)依照如下規(guī)則處理

? 發(fā)生SQLEXCEPTION錯誤邻邮,則執(zhí)行exit退出
? 發(fā)生SQLWARNING警告,則執(zhí)行contine繼續(xù)執(zhí)行
? 發(fā)生NOT FOUND情況克婶,則執(zhí)行continue繼續(xù)執(zhí)行

 比如SQLSTATE '23000'表示主鍵沖突錯誤
 mysql> CREATE TABLE t (s1 INT, PRIMARY KEY (s1));
 Query OK, 0 rows affected (0.00 sec)
 mysql> delimiter //
 mysql> CREATE PROCEDURE handlerdemo ()
 -> BEGIN
 -> DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
 -> SET @x = 1;
 -> INSERT INTO test.t VALUES (1);
 -> SET @x = 2;
 -> INSERT INTO test.t VALUES (1);
 -> SET @x = 3;
 -> END;
 -> //
 Mysql> delimiter ;
 mysql> CALL handlerdemo();
 mysql> SELECT @x;
 +------+
 | @x |
 +------+
 | 3 |
 +------+
 1 row in set (0.00 sec)

 CREATE PROCEDURE curdemo()
 BEGIN
 DECLARE done INT DEFAULT FALSE;
 DECLARE a CHAR(16);
 DECLARE b, c INT;
 DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
 DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
 OPEN cur1;
 OPEN cur2;
 read_loop: LOOP
 FETCH cur1 INTO a, b;
 FETCH cur2 INTO c;
 IF done THEN
 LEAVE read_loop;
 END IF;
 IF b < c THEN
 INSERT INTO test.t3 VALUES (a,b);
 ELSE
 INSERT INTO test.t3 VALUES (a,c);
 END IF;
 END LOOP;
 CLOSE cur1;
 CLOSE cur2;
 END;

操作

  1. 創(chuàng)建一個過程筒严,將男生和女生的學(xué)生數(shù)據(jù)分別存儲到男生表和女生表中。
create procedure proc1() as BeginInsert 
into students_male select * from students where gender=0;
Insert into students_female select * from students where gender=1;
End;
  1. 創(chuàng)建一個過程情萤,將每個學(xué)生的課程數(shù)鸭蛙,平均成績,及格課程數(shù)筋岛,非及格課程數(shù)都存放在單獨的表中
create procedure proc2() as BeginInsert 
into temp1 select sid,count(*),avg(score),sum(case when score>=60 then 1 else 0 end),
sum(case when score<60 then 1 else 0 end) from score group by sid;
End;
  1. 創(chuàng)建一個過程娶视,將學(xué)生sid作為輸入?yún)?shù),結(jié)果展示出該學(xué)生的課程數(shù)和平均成績
create procedure proc3(IN st_id) as Begin
select sid,count(*),avg(score) from score where sid=st_id group by sid;
End;
  1. 創(chuàng)建一個函數(shù)睁宰,以學(xué)生sid作為輸入?yún)?shù)肪获,將該學(xué)生的課程數(shù)和平均成績存放在單獨的表中,并返回平均成績
create function func1(st_id int) as Begin
return int 
declare avg_score int;
insert into temp2 select sid,count(*),avg(score) from score where sid=st_id group by sid;
select avg(score) into avg_score from score where sid=st_id group by Sid;
return avg_score; 
End;
  1. 用游標(biāo)的方法實現(xiàn)創(chuàng)建一個函數(shù)柒傻,輸入?yún)?shù)是老師的id孝赫,函數(shù)返回該老師所教授的課程數(shù)量,并將這些學(xué)習(xí)這些課程的每個學(xué)生如果成績不及格红符,把學(xué)生的sid和對應(yīng)課程名字寒锚、成績insert到表A中,如果成績及格违孝,把學(xué)生的sid和對應(yīng)的課程名字、成績insert到表B中
 delimiter //
 Create function func3(v_teacher_id int)
 Returns int
 Begin
 Declare n_course int;
 Declare v_sid int default null;
 Declare v_course_name varchar(60);
 Declare v_score int;
 Declare cur1 cursor for select a.sid,b.course_name,a.score
 From score a inner join course b on a.coure_id=b.id
 Where b.teacher_id=v_teacher_id;
 declare continue handler for not found set v_sid=null;
 Select count(*) into n_course from course where teacher_id=v_teacher_id;
 Open cur1;
 Fetch cur1 into v_sid,v_course_name,v_score;
 While v_sid is not null do
 If v_score<60 then
 insert into A select v_sid,v_course_name,v_score;
 Else
 insert into B select v_sid,v_course_name,v_score;
 End if;
 Fetch cur1 into v_sid,v_course_name,v_score;
 End while;
 Close cur1;
 Return n_course;
 End;
 //
 Delimiter ;

create trigger語句

? create trigger語句用來創(chuàng)建一個觸發(fā)器泳赋,觸發(fā)器的作用是當(dāng)表上有對應(yīng)SQL語句發(fā)生時雌桑,則觸發(fā)執(zhí)行
? 觸發(fā)器創(chuàng)建時需要指定對應(yīng)的表名tbl_name

CREATE
    [DEFINER = { user | CURRENT_USER }]
    TRIGGER trigger_name
    trigger_time trigger_event
    ON tbl_name FOR EACH ROW
    [trigger_order]
    trigger_body

trigger_time: { BEFORE | AFTER }

trigger_event: { INSERT | UPDATE | DELETE }

trigger_order: { FOLLOWS | PRECEDES } other_trigger_name

? Definer關(guān)鍵詞用來指定trigger的安全環(huán)境
? Trigger_time指定觸發(fā)器的執(zhí)行時間,BEFORE和AFTER指定觸發(fā)器在表中的每行數(shù)據(jù)修改前或者后執(zhí)行
? Trigger_event指定觸發(fā)該觸發(fā)器的具體事件
? INSERT當(dāng)新的一行數(shù)據(jù)插入表中時觸發(fā)祖今,比如通過執(zhí)行insert,load data,replace語句插入新數(shù)據(jù)
? UPDATE當(dāng)表的一行數(shù)據(jù)被修改時觸發(fā)校坑,比如執(zhí)行update語句時
? DELETE當(dāng)表的一行數(shù)據(jù)被刪除時觸發(fā)拣技,比如執(zhí)行delete,replace語句時
? 當(dāng)執(zhí)行insert into … on duplicate key update語句時,當(dāng)碰到重復(fù)行執(zhí)行update時耍目,則觸發(fā)update下的觸發(fā)器
? 從5.7.2版本開始膏斤,可以創(chuàng)建具有相同trigger_time和trigger_event的同一個表上的多個觸發(fā)器,默認(rèn)情況下按照創(chuàng)建的時間依次執(zhí)行邪驮,通過指定FOLLOWS/PRECEDES改變執(zhí)行順序莫辨,即FOLLOWS時表示新創(chuàng)建的觸發(fā)器后執(zhí)行,PRECEDES則表示新觸發(fā)器先執(zhí)行
? Trigger_body表示觸發(fā)器觸發(fā)之后要執(zhí)行的一個或多個語句毅访,在內(nèi)部可以引用涉及表的字段沮榜,OLD.col_name表示行數(shù)據(jù)被修改或刪除之前的字段數(shù)據(jù),NEW.col_name表示行數(shù)據(jù)被插入或修改之后的字段數(shù)據(jù)

 delimiter //
 create trigger simple_trigger
 after update
 on students for each row
 begin
 insert into students_bak values(old.sid,old.sname,new.sname,old.sex,new.sex,now());
 end;
 //
 delimiter ;
 mysql> update students set sname='abc',sex=1;
 mysql> select * from students_bak;
 +------+----------+----------+--------+--------+---------------------+
 | sid  | oldsname | newsname | oldsex | newsex | tstamp              |
 +------+----------+----------+--------+--------+---------------------+
 | 1    | a        | abc      | -1     | 1      | 2017-03-28 16:28:42 |
 | 2    | b        | abc      | -1     | 1      | 2017-03-28 16:28:42 |
 | 3    | c        | abc      | -1     | 1      | 2017-03-28 16:28:42 |
 +------+----------+----------+--------+--------+---------------------+

Drop trigger語句

? Drop trigger語句用來刪除一個觸發(fā)器

DROP TRIGGER [ IF EXISTS ] [數(shù)據(jù)庫名] <觸發(fā)器名>

? If exists短語用來避免刪除不存在的觸發(fā)器時引發(fā)報錯
? 當(dāng)你執(zhí)行drop table時喻粹,表上的觸發(fā)器也被drop掉了

 mysql> Drop trigger simple_trigger;
 Query OK, 0 rows affected (0.00 sec)

操作

  1. 在score表上創(chuàng)建一個觸發(fā)器蟆融,當(dāng)有新的數(shù)據(jù)插入時,在score_bak表里記錄新插入的數(shù)據(jù)的所有字段信息守呜,并用tstamp字段標(biāo)注數(shù)據(jù)的插入時間
 Delimiter //
 create trigger trig1
 after insert on score
 For each row
 Begin
 Insert into score_bak(Sid,course_id,score,tstamp) values(new.sid,new.course_id,new.score,now());
 End;
 //
 Delimiter ;
  1. 在score表上創(chuàng)建一個觸發(fā)器型酥,當(dāng)有新的數(shù)據(jù)插入時,在score_avg表里記錄對應(yīng)學(xué)生的所有課程的平均成績(注意查乒,如果在score_avg表里已經(jīng)有了學(xué)生的記錄弥喉,需要update)
 Delimiter //
 create trigger trig2
 After insert on score
 For each row
 Begin
 Declare n int;
 Select count(*) into n from score_avg where sid=new.sid;
 If n=1 then
 update score_avg set avg_score=(select avg(score) from score where sid=new.sid) where sid=new.sid;
 Else
 insert into score_avg select sid,avg(score) from score where sid=new.sid group by sid;
 End if;
 End;
 //
 Delimiter ; 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市侣颂,隨后出現(xiàn)的幾起案子档桃,更是在濱河造成了極大的恐慌,老刑警劉巖憔晒,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藻肄,死亡現(xiàn)場離奇詭異,居然都是意外死亡拒担,警方通過查閱死者的電腦和手機(jī)嘹屯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來从撼,“玉大人州弟,你說我怎么就攤上這事〉土悖” “怎么了婆翔?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掏婶。 經(jīng)常有香客問我啃奴,道長,這世上最難降的妖魔是什么雄妥? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任最蕾,我火速辦了婚禮依溯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瘟则。我一直安慰自己黎炉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布醋拧。 她就那樣靜靜地躺著慷嗜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪趁仙。 梳的紋絲不亂的頭發(fā)上洪添,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音雀费,去河邊找鬼干奢。 笑死,一個胖子當(dāng)著我的面吹牛盏袄,可吹牛的內(nèi)容都是我干的忿峻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼辕羽,長吁一口氣:“原來是場噩夢啊……” “哼逛尚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刁愿,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤绰寞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后铣口,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滤钱,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年脑题,在試婚紗的時候發(fā)現(xiàn)自己被綠了件缸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡叔遂,死狀恐怖他炊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情已艰,我是刑警寧澤痊末,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站哩掺,受9級特大地震影響舌胶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疮丛,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一幔嫂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧誊薄,春花似錦履恩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至片吊,卻和暖如春绽昏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俏脊。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工全谤, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爷贫。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓认然,卻偏偏與公主長得像,于是被迫代替她去往敵國和親漫萄。 傳聞我的和親對象是個殘疾皇子卷员,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348