您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關怎么理解MySQL存儲過程和觸發器,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
存儲過程(stored procedure SP)是MySQL 5.0 版本中的最大創新。他們是一些由MySQL服務器直接存儲和執行的定制過程 或 函數。SP的加入把SQL語言擴展成了一種程序設計語言,可以利用SP把一個客戶--服務器體系的數據庫應用軟件中的部分邏輯保存起來供日后使用。
觸發器(trigger) 是在INSERT ,UPDATE 或 DELETE 命令之前或者之后對SQL命令或SP的自動自動調用。
----------------------------------------
//輸入都必須以 '$$'作為結束符號
delimiter $$
我們先來創建一個最簡單的函數,
函數的功能是寫入兩個數,得出 和:
Create FUNCTION addition(v1 int(11),v2 int(11))
RETURNS int(11)
BEGIN
return (v1+v2);
END$$
//把結束符號換回來
delimiter ;
讓我們來調用我們的函數:
select addition(11,15) ; 結果 26 正確。
讓我們來查看一下數據庫中有那些函數
show function status;
如何來查看addition的代碼?
show create function addition;
現在讓我們來刪除那個函數:
drop function addition;
----------------------------------------
上面是小試牛刀。 現在開始我們來全面學習MYSQL中的存儲過程 和 觸發器
分3個類 FUNCTION , PROCEDURE ,TRIGGER 來學習研究。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
FUNCTION
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
語法 :
CREATE FUNCTION function_name (param1 datatype [,param2 datatype ,.....])
RETURNS datatype
BEGIN
commands;
END
---------------------------------------------------------------------------
SP 注釋
"--" 開始并且一直到這一行的結尾都是注釋
------------------------------------------
(1)FUNCTION 中的局部變量的定義 和 變量的賦值
* 變量的定義
語法 :
DECLARE varname1 datatype1 [DEFAULT value];
DECLARE varname1,varname2 .... datatype [DEFAULT value]; //多變量同類型的定義方式
$ 變量的定義要在BEGIN ... END 之間定義。
$ 如果在FUNCTION 體中定義了多個BEGIN ... END 嵌套,那么 變量的定義只能在當前 BEGIN .. END 或則 子 BEGIN ... END 中有效。
$ 子類 BEGIN ... END 中的變量定義可以覆蓋父類 BEGIN ... END 中定義的變量。
* 對變量的賦值
對變量的賦值有兩種方法。
[1]直接給變量賦給常量,或則把其他的變量賦值給當前變量
set var = value;
set var1 = value1,var2 = value2....;
[2]把SQL查詢結果賦值給變量
SELECT var := value //一種以SELECT 方法 把常量或其他變量賦值給當前變量的方法
SELECT nomalvalue INTO var //又一種以SELECT 方法 把常量或其他變量賦值給當前變量的方法
SELECT value FROM TABLE .. INTO var;
SELECT value1,value2 FROM TABLE .. INTO var1,var2;
SELECT INTO 命令是SELECT 命令的一種變體。 它上一以 INTO varname 結束整條命令。
要求,SELECT命令返回并且只能返回一條記錄。(不允許多條記錄)
example-001:
use wyd
delimiter $$
----------------------
create table person(
id int primary key auto_increment,
age int
) $$
----------------------
insert into person(age)values(12);
insert into person(age)values(34);
insert into person(age)values(42);
insert into person(age)values(13);
insert into person(age)values(2)$$
-----------------------
drop function addtion$$
----------------------
CREATE FUNCTION getage(person_id int)
RETURNS int
BEGIN
DECLARE person_age int default 0;
SELECT age FROM person WHERE id = person_id INTO person_age;
RETURN person_age;
END$$
----------------------
test the result:
select getage(1)$$ --> result = 12
select getage(2)$$ --> result = 34
運行正常
------------------------------------------------
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(2)FUNCTION 中的分支
[1] IF - THEN - ELSE 分支
語法 :
IF comdition THEN
commands;
END IF;
-------------------------
IF comdition THEN
commands;
ELSE
commands
END IF;
-------------------------
嵌套 IF comdition THEN
commands;
ELSE IF comdition THEN
commands;
[ELSE commands;]
END IF;
END IF;
-------------------------
[2] CASE 分支
語法:
--------------------------------
CASE expression
WHEN value1 THEN commands;
WHEN value2 THEN commands;
.......
WHEN value_n THEN commands;
ELSE commands;
END CASE;
--------------------------------
example-002:
CREATE FUNCTION personstate (age int)
RETURNS varchar(30)
BEGIN
DECLARE personstate varchar(30) DEFAULT "UNKNOWN";
IF age < 0 THEN SET personstate = "UNBORN";
ELSE
SET personstate = "BORN";
END IF;
RETURN personstate;
END$$
-----------------
select personstate(-3) ----> result = UNBORN;
select personstate(3) ----> result = BORN;
------------------------------------
example-003:
DROP FUNCTION personstate$$
CREATE FUNCTION personstate (age int)
RETURNS varchar(30)
BEGIN
DECLARE personstate varchar(30) DEFAULT "UNKNOWN";
IF age < 0 THEN SET personstate = "UNBORN";
ELSE
IF age >0 && age<=14 THEN SET personstate ="CHILD"; END IF;
IF age >14 && age <=22 THEN SET personstate ="YANG"; END IF;
IF age >22 && age<60 THEN SET personstate = "STRONG"; END IF;
IF age >60 THEN SET personstate = "OLD"; END IF;
END IF;
RETURN personstate;
END$$
---------
select personstate(-3)$$ result = UNBORN
select personstate(5)$$ result = CHILD
select personstate(16)$$ result = YANG
select personstate(28)$$ result = STRONG
select personstate(66)$$ result = OLD
TEST IS OK.
----------------------------------------
example-004:
DROP FUNCTION showIn$$
CREATE FUNCTION showIn( valueIn int)
RETURNS VARCHAR(50)
BEGIN
DECLARE str varchar(30) DEFAULT "UNKNOWN";
CASE valueIn
WHEN 1 THEN SET str = "you input is 1";
WHEN 2 THEN SET str = "you input is 2";
WHEN 3 THEN SET str = "you input is 3";
WHEN 4 THEN SET str = "you input is 4";
WHEN 5 THEN SET str = "you input is 5";
ELSE SET str = "you input is not 1,2,3,4,5";
END CASE;
RETURN str;
END$$
-------------------
select showIn(1)$$ result = you input is 1
select showIn(2)$$ result = you input is 2
select showIn(6)$$ result = you input is not 1,2,3,4,5
TEST IS OK
----------------------------------------
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(3)FUNCTION 中的循環
[1] REPEAT-UNTIL 循環
[2] WHILE 循環
[3] LOOP 循環
* REPEAT-UTIL 循環
語法:
[loopname:] REPEAT
commands;
UNTIL condition
END REPEAT [loopname];
說明:
和 do {} while(condition) 語句的功能一樣。先運行,后判斷。
當condition 為true的時候 放棄循環
* WHILE 循環
語法:
[loopname :] WHILE condition DO
commands;
END WHILE [loopname];
說明: 和 while(condition) {commands; } 語句功能一樣。 先判斷,后執行。
當condition 為 false 的時候 放棄循環
* LOOP 循環
語法:
loopname: LOOP
commands;
IF condition THEN LEAVE loopname ; END IF;
END LOOP loopname;
說明 : 這是一個沒有條件判斷的循環。可以認為是一個死循環。
除非執行LEAVE 命令來跳出循環,否則循環將永遠被執行。
* LEAVE
語法:
LEAVE loopname ;
說明:
LEAVE loopname 命令見是程序代碼的執行流程跳出并且結束一個循環。
LEAVE loopname 命令還可以用來提前退出BEGIN - END 語句塊。
LEAVE loopname 命令相當于 C 或則 JAVA中 跳出循環的 BREAK 命令
* ITERATE
語法:
ITERATE loopname ;
說明:
TERATE loopname 命令是跳出當次循環,接下來執行下一次循環。
TERATE loopname 命令只能在循環體內運行。
TERATE loopname 命令相當于 C 或則 JAVA中 跳出循環的 CONTINUE 命令
-------------------------
example-005:
DROP FUNCTION getString$$
CREATE FUNCTION getString(number int(11))
RETURNS VARCHAR(50)
BEGIN
declare str varchar(50) default '';
declare i int default 0;
myloop: REPEAT
SET i = i+1;
set str = concat(str,"*");
UNTIL i>=number
END REPEAT myloop;
RETURN str;
END $$
-------------
select getString(3)$$
select getString(4)$$
select getString(8)$$
TEST IS OK
-------------------------
example-006:
DROP FUNCTION getString$$
CREATE FUNCTION getString(number int(11))
RETURNS VARCHAR(50)
BEGIN
declare str varchar(50) default "";
declare i int default 0;
myloop: WHILE i<number DO
set i = i+1;
set str = concat(str,"@");
END WHILE myloop;
return str;
END$$
--------
select getString(3)$$
select getString(4)$$
select getString(8)$$
TEST IS OK
-------------------------
example-007:
DROP FUNCTION getString$$
CREATE FUNCTION getString(number int(11))
RETURNS VARCHAR(50)
BEGIN
declare str varchar(50) default "";
declare i int default 0;
myloop:LOOP
set i = i+1;
IF i>number THEN LEAVE myloop; END IF;
set str= concat(str,"# ");
END LOOP myloop;
RETURN str;
END$$
---------
select getString(3)$$
select getString(4)$$
select getString(8)$$
TEST IS OK
-----------------------------
-----------------------------
example-iterate :
DROP FUNCTION getString$$
CREATE FUNCTION getString(number int(11))
RETURNS VARCHAR(50)
BEGIN
declare str varchar(50) default "";
declare i int default 0;
myloop:LOOP
set i = i+1;
IF i%2 = 0 THEN ITERATE myloop ; END IF;
IF i>number THEN LEAVE myloop; END IF;
set str= concat(str,"# ");
END LOOP myloop;
RETURN str;
END$$
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
基本語法規則 <摘錄mysql 5.0="" p="" 296-297="">
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
通過對FUNCTION的了解,我們已經對SP的語法規則有了大體的了解。
在FUNCTION 中的變量定義規則,變量賦值規則,分支規則 和 循環規則 同樣也適用于 PROCEDURE。
現在我們來對SP的語法規則進行規范的認識:
# 分號 (;) 。 同一個SP可以包含任意多條SQL命令。這些命令必須用分號格開,就連分支和循環的控制結構也必須用分號結束。
# BEGIN - END 。 沒有落在SP關鍵字之間(如 THEN 和 END IF 之間) 的多條SQL命令必須放在關鍵字BEGIN 和 END 之間。
這就意味著由多條SQL命令構成的SP的代碼都必須以BEGIN開始,以END結束。
# 換行符。 換行符在SP代碼中的語意效果與空格字符相同。這意味著把 IF-THEN-ELSE-END-IF 結構連續寫在同一行或分開寫在多行上都是可以的。
# 變量 。 供SP內部使用的局部變量 和 局部參數不加 "@" 前綴。 在SP內允許使用普通的SQL變量,但是他們必須加上"@"前綴。
(加"@"前綴的變量是普通全局變量。對變量疑問,可以參考 《MYSQL變量》 這個部分。)
# 字母大小寫情況。 SP 在定義 和調用時均不分字母大小寫情況。它寫成(比如說)shorten , SHORTEN , Shorten 的效果都是一樣的。
# 特殊字符。 在SP中避免使用特殊字符。 總之MYSQL對特殊字符的支持還不是很好。
# 注釋。 "--" 開始并且一直到這一行的結尾都是注釋
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
查看和刪除SP的方法
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
(1) 查看FUNCTION
show function status
show CREATE FUNCTION functionname
select routine_name ,routine_type,routine_schema,created from information_schema.routines where routine_schema = '你的數據庫名' and routine_type='FUNCTION'
例如:
select routine_name ,routine_type,routine_schema,created from information_schema.routines where routine_schema = 'WYD' and routine_type='function'
DROP FUNCTION [IF EXISTS] function_name
(2) 查看PROCEDURE
SHOW PROCEDURE STATUS
show CREATE PROCEDURE functionname
select routine_name ,routine_type,routine_schema,created from information_schema.routines where routine_schema = '你的數據庫名' and routine_type='PROCEDURE'
例如:
select routine_name ,routine_type,routine_schema,created from information_schema.routines where routine_schema = 'WYD' and routine_type='PROCEDURE'
DROP PROCEDURE [IF EXISTS] procedure_name
(3) 查看所有SP
desc information_schema.routines
select routine_name ,routine_type,routine_schema,created from information_schema.routines
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
MYSQL變量
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
MYSQL允許人們把簡單的值(離散值,不是象SELECT查詢結果那樣的集合或列表)保存在變量里。在日常應用里,需要用到MySQL變量的時候不多;但是對存儲過程來說,變量卻是非常重要的SQL元素。MySQL里的變量可以分為3類:
$ 普通變量。
這類變量的標志是以字符@開頭,他們在SQL連接被關閉時將失去內容。
$ 系統變量和服務器變量。
這類變量的內容是MySQL服務器的工作狀態或屬性,他們的標志是以"@@"字符串開頭。
$ 存儲過程里的局部變量。
這些變量是在存儲過程內部聲明的,只在存儲過程內有效。他們沒有統一的特殊標志,但是變量名必須與數據表和數據列名區別。
局部變量在使用前必須要用DECLARE命令對他們做出聲明。局部變量的內容在過程或函數退出的時候丟失。
普通全局變量的聲明和賦值:
例子: set @varname = 3
select @total :=count(*) from table_a
select money from book where id =3 into @bookmoney
查詢:
例子: select @varname
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
PROCEDURE
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
PROCEDURE [databasename.]procedure_name([IN or OUT or INOUT ] parametername datatype )
BEGIN
commands;
END
----------------
存儲過程的參數:
關鍵字 IN ,OUT ,INOUT 用來區分有關參數的用途是僅限制于輸入數據、僅限于輸出數據 還是 輸入輸出數據均可的。(默認設置是IN)
----------------
PROCEDURE局部變量的定義和局部變量的賦值
:同FUNCTION的局部變量的定義和局部變量的賦值
-----------------
example-007:
題目:寫一個加法的PROCEDURE, 輸入兩個數字。PROCEDURE輸出他們的和
delimiter $$
DROP PROCEDURE IF EXISTS p_addition
CREATE PROCEDURE p_addition(IN v1 int, IN v2 int ,OUT sum int)
BEGIN
set sum = v1+v2;
END$$
---------
CALL p_addition(12,45,@sum)$$
select @sum $$
TEST IS OK
----------------------------------
----------------------------------
example-008
題目: 有一張student表,有學生名字段和總分字段。
我們寫一個PROCEDURE,只要調用這個PROCEDURE ,輸入 學生名 和 總分。 它就幫助我們把該學生寫入數據表中。
delimiter $$
CREATE TABLE student(
id int(11) primary key auto_increment,
name varchar(50),
score int(5)
)$$
-----
DROP PROCEDURE IF EXISTS p_addStudent$$
-----
CREATE PROCEDURE p_addStudent(IN p_name VARCHAR(50) ,IN p_score INT)
BEGIN
insert into student(name,score)values(p_name,p_score);
END$$
-----
CALL p_addStudent('Petter',199)$$
CALL p_addStudent('Helen',209)$$
CALL p_addStudent('Jacker',238)$$
select * from student $$
--------TEST IS OK
--------------------------------------
--------------------------------------
example-009
題目: 有一張person表 表中有多個字段。
name ,age , state
我們寫一個PROCEDURE,只要調用這個PROCEDURE ,輸入人名 和 年齡。 它就幫我們判斷state,并寫入數據庫。
如果年齡<0 ,state = 'UNBORN'
0 <=如果年齡<12,state = 'CHILD'
12<=如果年齡<22,state = 'YANG'
22<=如果年齡<60,state = 'STRONG'
60<=如果年齡,state = 'OLD'
delimiter $$
drop table person$$
create table person(
id int(11) primary key auto_increment,
name varchar(50),
age int(3),
state varchar(50)
)$$
DROP PROCEDURE IF EXISTS p_addPerson $$
CREATE PROCEDURE p_addPerson(IN p_name varchar(50),IN p_age INT(3))
BEGIN
declare p_state varchar(50) default "UN_KNOW";
IF p_age < 0 THEN SET p_state = "UNBORN";
ELSE
IF p_age >0 && p_age<12 THEN SET p_state ="CHILD"; END IF;
IF p_age >=12 && p_age<22 THEN SET p_state ="YANG"; END IF;
IF p_age >=22 && p_age<60 THEN SET p_state = "STRONG"; END IF;
IF p_age >=60 THEN SET p_state = "OLD"; END IF;
END IF;
INSERT INTO person(name,age,state) values(p_name,p_age,p_state) ;
END$$
------------------
CALL p_addPerson('Pet',11) $$
CALL p_addPerson('Tom',21) $$
CALL p_addPerson('Joy',74) $$
CALL p_addPerson('Soy',-4) $$
SELECT * from person $$
----- TEST IS OK ----
--------------------------------------------------
--------------------------------------------------
example-010
題目:有一張表 goods ,3個字段 id ,name,price. 表中有很多記錄。
現在我們要寫一個PROCEDURE ,把里面的每個商品的價格都修改為原來的80%.
delimiter $$
drop table goods$$
create table goods(
id int(11) primary key auto_increment,
name varchar(50),
price float(6,2) default 0000.00
)$$
insert into goods(name,price)values('goods_01',77.56)$$
insert into goods(name,price)values('goods_02',147.56)$$
insert into goods(name,price)values('goods_03',156.36)$$
insert into goods(name,price)values('goods_04',58.36)$$
insert into goods(name,price)values('goods_05',458.68)$$
insert into goods(name,price)values('goods_06',485.55)$$
insert into goods(name,price)values('goods_07',785.22)$$
insert into goods(name,price)values('goods_08',45.36)$$
insert into goods(name,price)values('goods_09',47.36)$$
insert into goods(name,price)values('goods_10',456.36)$$
insert into goods(name,price)values('goods_11',654.85)$$
insert into goods(name,price)values('goods_12',785.25)$$
------------
DROP PROCEDURE IF EXISTS p_goods $$
CREATE PROCEDURE p_goods()
BEGIN
DECLARE p_id INT DEFAULT 0;
DECLARE p_id_min INT DEFAULT 0;
DECLARE p_id_max INT DEFAULT 0;
DECLARE p_id_current INT DEFAULT 0;
DECLARE p_name_current VARCHAR(50) DEFAULT "UNKNOW";
DECLARE p_price FLOAT(6,2) DEFAULT 0;
select min(id),max(id) from goods into p_id_min ,p_id_max;
SET p_id = p_id_min;
goods_loop : LOOP
select id,name,price from goods where id = p_id into p_id_current,p_name_current,p_price;
IF p_id_current!=0 THEN
set p_price = p_price * 0.8;
update goods set price = p_price where id = p_id;
set p_id_current=0;
END IF;
set p_id = p_id + 1;
IF p_id > p_id_max THEN LEAVE goods_loop; END IF;
END LOOP goods_loop;
END $$
------------------------------------
mysql> select * from goods;
-> $$
+----+----------+--------+
| id | name | price |
+----+----------+--------+
| 1 | goods_01 | 77.56 |
| 2 | goods_02 | 147.56 |
| 3 | goods_03 | 156.36 |
| 4 | goods_04 | 58.36 |
| 5 | goods_05 | 458.68 |
| 6 | goods_06 | 485.55 |
| 7 | goods_07 | 785.22 |
| 8 | goods_08 | 45.36 |
| 9 | goods_09 | 47.36 |
| 10 | goods_10 | 456.36 |
| 11 | goods_11 | 654.85 |
| 12 | goods_12 | 785.25 |
+----+----------+--------+
----------------------------------------
CALL p_goods() $$
----------------------------------------
mysql> CALL p_goods() $$
Query OK, 1 row affected (0.13 sec)
mysql> select *from goods$$
+----+----------+--------+
| id | name | price |
+----+----------+--------+
| 1 | goods_01 | 62.05 |
| 2 | goods_02 | 118.05 |
| 3 | goods_03 | 125.09 |
| 4 | goods_04 | 46.69 |
| 5 | goods_05 | 366.94 |
| 6 | goods_06 | 388.44 |
| 7 | goods_07 | 628.18 |
| 8 | goods_08 | 36.29 |
| 9 | goods_09 | 37.89 |
| 10 | goods_10 | 365.09 |
| 11 | goods_11 | 523.88 |
| 12 | goods_12 | 628.20 |
+----+----------+--------+
12 rows in set (0.00 sec)
---------------------------------------
example-010 TEST IS OK ,Finished
---------------------------------------
---------------------------------------
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
異常捕獲
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
SP里面的SQL命令在執行的過程中可能會出錯,所以MYSQL也像其他一些程序語言一樣向程序員提供一種利用 ‘異常處理器’來響應和處理這類錯誤的機制。
在一個BEGIN - END 語句塊里,對‘異常處理器’的定義必須出現在變量,光標,出錯條件的聲明之后。在其他SQL命令之前。
語法:
DECLARE type HANDLER FOR condition1[,condition2,condition3,.......] handler_action
下面對語法中的type , condition , handler_action 來進行解釋:
<1>type(異常捕獲處理類型) 。可以選擇的類型目前只有 CONTINUE 和 EXIT 兩種。(未來的MySQL版本可能會增加第3種選擇:UNDO)
CONTINUE : 如果當前命令在執行時發生錯誤,繼續執行下一條命令。
EXIT : 如果當前命令在執行時發生錯誤,跳出當前的BEGIN - END 語句塊。
<2>condition (捕獲異常條件)。這里可以列出一個到多個捕獲異常條件。它們是異常處理器要捕捉的目標。捕獲異常條件可以用以下幾種方式給出:
SQLSTATE 'errorcode' 單個SQL異常代碼,編號是errorcode
SQLWARNING 含蓋了SQLSTATE編號為01nnn的所有異常
NOT FOUND 含蓋了所有其他的(即SQLSTATE編號不是01 和 02開頭的)的異常
mysqlerrorcode 這個數字是MySQL異常的代碼而不是一個SQLSTATE異常的代碼
conditionname 用一個DECLARE CONDITION 命令定義的異常,conditionname是異常的名字
<3>handler_action 異常被拋出時要執行的命令。它將在異常拋出后, CONTINUE or EXIT 執行前運行。
因為這里只能放上一條命令,所以通常它是一個變量賦值命令。
-------------------------------------------------------------------
聲明異常捕獲條件(自定義異常)
所謂的"聲明異常捕獲" 就是給異常編碼定義一個簡明易記的名字。
定義一定要在異常出現以前定義。定義出來的異常捕獲名可以用在出錯的異常捕獲器定義中。
語法:
DECLARE condition_name CONDITION FOR {SQLSTATE sqlstate_code | MySQL_error_code};
例:
DECLARE foreign_key_error CONDITION FOR 1216;
DECLARE CONTINUE HANDLER FOR foreign_key_error MySQL_statements;
優先級:
當同時使用MySQl錯誤碼,標準SQLSTATE錯誤碼,命名條件(SQLEXCEPTION)來定義錯誤處理時,其捕獲順序是(只可捕獲一條錯誤):
MySQl錯誤碼--->SQLSTATE錯誤碼--->命名條件(SQLEXCEPTION)
具體的SQL_STATE 請參考
--------------------------------------------------------------------
異常的觸發
MYSQL中異常的出發只能靠執行非法代碼來實現。 而不能如同Oracle,直接有"RAISE Exception"來實現的。
--------------------------------------------------------------------
SP中的打印語句。
我們在Oracle中寫存儲過程,會很常用到一個打印函數“DBMS_OUTPUT.PUT_LINE('要打印的內容');”
很可惜,在MySQL中沒有類似的函數。
但是我們可以通過變通來實現該功能。
利用 SELECT '我們想要讓計算機打印出來的內容' 來實現。
語法:
SELECT "Content" as result;
SELECT CONCAT(A1,A2[,A3,A4,.....]) as result ;
寫一個例子:
example-011
delimiter $$
--------
DROP PROCEDURE IF EXISTS p_print $$
--------
CREATE PROCEDURE p_print()
BEGIN
DECLARE i int default 1;
myloop : LOOP
select concat("這是第",i,"次顯示數據") as printResult;
set i=i+1;
IF i>10 THEN LEAVE myloop; END IF;
END LOOP myloop;
END$$
---------
call p_print()$$
----------------------------------------
example-012
寫一個循環 ,我們來循環捕捉錯誤。
delimiter $$
--------------
DROP PROCEDURE IF EXISTS p_exception $$
--------------
CREATE PROCEDURE p_exception()
BEGIN
DECLARE num int default 0;
DECLARE table_notfound_error CONDITION FOR 1146 ;
DECLARE CONTINUE HANDLER FOR table_notfound_error SELECT CONCAT("TABLE is not exit FOR ---",num) as message;
myloop:LOOP
set num = num + 1;
select * from exception; -- 1146 errorcode
IF num >= 10 THEN
LEAVE myloop;
END IF;
END LOOP myloop;
END$$
-----------------
TEST IS OK
-----------------------------------------------------
-----------------------------------------------------
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
游標
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
說起游標,我就想起了Oracle中的游標。 如果你沒有學習過Oracle中的游標,沒有關系。因為MYSQL的游標更簡單。
游標(CURSOR):是構建在MYSQL中,用來查詢數據,獲得記錄集合的指針。他可以讓開發者一次訪問結果集中一行。
MYSQL 中只有顯式游標 這 一種游標。
--------------------------------
游標的使用方法(使用過程)。
(1)聲明游標。
(2)打開游標。
(3)從游標中獲取記錄。
(4)關閉游標。
---------------------------------
(1)聲明游標。
語法 :
DECLARE cursorname CURSOR FOR "YOUR SQL";
--------
(2)打開游標。
OPEN cursorname;
--------
(3)從游標中獲取記錄。
FETCH cursorname INTO v1,v2,....;
在ORACEL 中,游標中沒有數值的時候 %FOUND 就會 返回一個 FALSE。
但是在MYSQL 中FETCH 到最后就會觸發一個1329號錯誤 "No data to fetch".相應的SQLSTATE 為 02000。
這個異常是無法避免的,所以我們都會用異常捕捉器來捕捉它。(可以直接聲明一個對應的異常捕捉器,也可以聲明一個 NOT FOUND 的異常捕捉器)
---------
(4)關閉游標。
CLOSE cursorname 。
注釋: 其實這樣做 也就增加邏輯性。其實光標會在BEGIN - END 塊結束的時候自動關閉。所以很多程序員都不會手動關閉游標。
-----------------------
實例練習:
example-013
題目,創建一個多字段的表 student ,有 id, name ,intime 三個字段。里面寫入有多行記錄。
用游標來獲得里面的所有 記錄,并且 一行一行的輸出。
--------------
delimiter $$
--------------
DROP TABLE IF EXISTS student $$
--------------
CREATE TABLE student(
id int primary key auto_increment,
name varchar(50),
intime timestamp(14)
)$$
--------------
insert into student(name,intime) values('s-1','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-2','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-3','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-4','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-5','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-6','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-7','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-8','1999-08-25 12:30:30')$$
insert into student(name,intime) values('s-9','1999-08-25 12:30:30')$$
commit $$
---------------
DROP PROCEDURE IF EXISTS p_readcursor $$
---------------
CREATE PROCEDURE p_readcursor()
BEGIN
DECLARE p_id int default 0;
DECLARE p_name varchar(50) default "unknow";
DECLARE p_intime timestamp(14) default '0000-00-00 00:00:00';
DECLARE student_cursor CURSOR FOR select id,name,intime from student;
DECLARE EXIT HANDLER FOR 1329 SELECT "CURSOR IS END --> OK" as message;
OPEN student_cursor;
myloop: LOOP
FETCH student_cursor into p_id,p_name,p_intime;
IF p_id=100 THEN LEAVE myloop; END IF;
select p_id,p_name,p_intime ;
END LOOP myloop;
CLOSE student_cursor;
END $$
----------------
call p_readcursor()$$
-------TEST IS OK----------
---------------------------
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
觸發器
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
觸發器的用途是 在INSERT 、UPDATE 、DELETE命令之前 或則 之后自動調動SQL命令或SP。比如說,可以為每一個UPDATE操作測試被修改的數據是否滿足特定條件。
在MYSQL5.0里邊觸發器還很不完善。與SP相比,觸發器還遠沒有成熟到可以用于實際應用程序中的地步。根據MySQL在線文檔里的說法,MYSQL5.1版本中將提供更多觸發器的功能。
在5.1版本出來以前,觸發器只能完成一些很初級的任務。
(1)創建觸發器
(2)查詢數據庫中的觸發器
(3)刪除觸發器
------------------------------
(1) 創建觸發器
語法:
CREATE TRIGGER trigger_name BEFORE|AFTER INSERT|UPDATE|DELETE
ON tablename [FOR EACH ROW]
BEGIN
commands;
END
注釋: * 最多可以為同一個數據表定義6個觸發器,分別為 INSERT , UPDATE 或 DELETE 命令的前 , 后各定義一個。
* 觸發器的名字在同一個數據庫中必須唯一。
* 觸發器代碼體要 以 BEGIN 開始, END 結束。
功能局限:
* 觸發器代碼里無法訪問任何數據表,就連觸發器為之定義的那個數據表也不能訪問。自然就不能使用 DELETE,UPDATE,INSERT 來修改數據庫表。
* MySQL沒有提供可以用來取消DELETE,UPDATE,INSERT命令的命令或語法元素。
* 在觸發器代碼里不能調用事務命令。
OLD and NEW
在觸發器代碼里,可以通過以下方式去訪問當前記錄的各個字段。
OLD.columname 返回一條現有記錄在被刪除或修改之前的內容(UPDATE,DELETE).
NEW.columname 返回一條新記錄或被修改記錄的新內容(INSERT ,UPDATE).
---------------------------------
(2)查詢數據庫中的觸發器
暫時還沒相關命令來查看自定義的觸發器。(他們做地太差了,HOHO)
---------------------------------
(3)刪除觸發器
語法:
DROP TRIGGER [databasename.]triggername
注釋: 刪除trigger不支持 IF EXISTS 變體。
---------------------------------
做一個例子:
example-014
delimiter $$
--------------
DROP TABLE IF EXISTS student_score$$
--------------
CREATE TABLE student_score (
id int primary key auto_increment,
name varchar(50),
score int
)$$
--------------
DROP TRIGGER student_score_insert_before$$
--------------
CREATE TRIGGER student_score_insert_before
BEFORE INSERT ON student_score FOR EACH ROW
BEGIN
IF NEW.score<0 or="" new.score="">100 THEN
SET NEW.score = 0;
END IF;
END$$
--------------
Insert into student_score(name,score)values('ZhangSan',12)$$
Insert into student_score(name,score)values('LiSi',-12)$$
Insert into student_score(name,score)values('WangWu',112)$$
mysql> select * from student_score$$
+----+----------+-------+
| id | name | score |
+----+----------+-------+
| 1 | ZhangSan | 12 |
| 2 | LiSi | 0 |
| 3 | WangWu | 0 |
+----+----------+-------+
筆記結束,祝賀大家學習愉快.
上述就是小編為大家分享的怎么理解MySQL存儲過程和觸發器了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。