Mysql(7)---存儲過程
存儲過程接下來會有三篇相關博客
- 第一篇存儲過程常用語法。
- 第二篇存儲過程中的游標。
- 第三篇單獨講一個實際開發過程中復雜的真實的案例。
一、概述
1、什么是存儲過程
概述
:簡單的說,就是一組SQL語句集
,功能強大,可以實現一些比較復雜
的邏輯功能,類似於JAVA語言中的方法;
說明
:存儲過程跟觸發器有點類似,都是一組SQL集,但是存儲過程是主動調用的,且功能比觸發器更加強大,觸發器是某件事觸發后自動調用。
2、優點
- 提高代碼的重用性
- 簡化操作
- 減少了編譯次數並且減少了和數據庫服務器的連接次數,提高了效率
二、delimiter命令
講存儲過程先講下delimiter命令。我們都知道sql語句默認都是以分號';'解釋。如果下select * from test_table;
這個會有一個問題對於存儲過程:
CREATE PROCEDURE `proc_if`(IN type int)
BEGIN
DECLARE c varchar(500);
IF type = 0 THEN
set c = 'param is 0';
ELSEIF type = 1 THEN
set c = 'param is 1';
ELSE
set c = 'param is others, not 0 or 1';
END IF;
select c;
END;
對於上面的存儲過程,它們應該是一個整體,應該是一起執行,而不是遇到分號
就執行。默認情況下,不可能等到用戶把這些語句全部輸入完之后,再執行整段語句。 因為mysql一遇到分號,它就要自動執行。 即,在語句遇到';'時,mysql解釋器就要執行了。 這種情況下,就需要事先把delimiter換成其它符號,如//或$$。
這個時候delimiter
命令就起作用了。
示例
# 這路我們講默認的 ; 結尾改成 $ 再執行下面語句
DELIMITER $
select * from mall_pro ;
select * from member ;
會發現能之前能正常執行的語句這里報錯了,因為現在修改結尾標志為 $
如果我們改成:
select * from mall_pro $
select * from member $
重點
:delimiter作用域是會話級別的,當你設置了DELIMITER $
那么在當前會話級別都是變成以$結束。
附一個詳細講delimiter的博客:MySql中 delimiter 詳解
三、存儲過程語法
1、創建
CREATE PROCEDURE 存儲過程名(參數列表)
BEGIN
# 存儲過程體(一組合法的SQL語句)
END
2、參數說明
1) 參數列表包含三部分
參數模式 參數名 參數類型
舉例:
in stuname varchar(20)
也可以寫成stuname varchar(20) 但最好把 in 加上。
2) 參數模式
in:該參數可以作為輸入,也就是該參數需要調用方傳入值。
out:該參數可以作為輸出,也就是該參數可以作為返回值。
inout:該參數既可以作為輸入又可以作為輸出,也就是該參數既需要傳入值,又可以返回值。
3、調用
CALL 存儲過程名(實參列表);
4、刪除
如果存在該存儲過程 則刪除該存儲過程。
drop procedure if exists 存儲過程名稱
重點
:存儲過程體中的每條sql語句的結尾要求必須加分號
。
注意
:如果存儲過程體僅僅只有一句話,begin end可以省略。
注意
:存儲過程的結尾可以使用 delimiter 重新設置(一般如果存儲過程中存在多個分號結尾,就可以使用delimiter)
5、示例
1)空參列表
# 案例:插入到admin表中五條記錄
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $
# 調用
CALL myp1()$
2):創建帶in模式參數的存儲過程
## 創建存儲過程實現 根據女神名,查詢對應的男神信息
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
SELECT bo.*
FROM boys bo
RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name=beautyName;
END $
# 調用
CALL myp2('柳岩')$
注意
:如果傳參帶有中文,如果上面這樣會報字符轉換錯誤,需要將VARCHAR(20)
改成NVARCHAR(20)
,這個我會將在 Mysql(10)---自定義函數 博客中說明。
3) :創建存儲過程實現,用戶是否登錄成功
CREATE PROCEDURE myp4(IN username VARCHAR(20),IN PASSWORD VARCHAR(20))
BEGIN
DECLARE result INT DEFAULT 0;# 聲明並初始化
SELECT COUNT(*) INTO result# 賦值
FROM admin
WHERE admin.username = username
AND admin.password = PASSWORD;
SELECT IF(result>0,'成功','失敗');# 使用
END $
# 調用
CALL myp3('張飛','8888')$
4) 帶有IN 和 OUT 參數
CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT)
BEGIN
SELECT boys.boyname ,boys.usercp INTO boyname,usercp
FROM boys
RIGHT JOIN
beauty b ON b.boyfriend_id = boys.id
WHERE b.name=beautyName ;
END $
# 調用
CALL myp7('小昭',@name,@cp)$ # 注意OUT的變量一定要是用戶自定義的用戶變量。
SELECT @name,@cp$
5) 創建帶inout模式參數的存儲過程
# 傳入a和b兩個值,最終a和b都翻倍並返回
DELIMITER $
CREATE PROCEDURE myp8(INOUT a INT ,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2;
END $
# 調用
SET @m=10$
SET @n=20$
CALL myp8(@m,@n)$
# 輸出 20 和 40
SELECT @m,@n$
這里都是舉了寫簡單的例子,后面會根據實際開發過程寫一個復雜的存儲過程。
三、流程控制結構
我們知道java對於流程控制有:if、switch。對於Mysql也一樣,它有它自己的流程控制語句,下面我們一個一個來分析。
1、IF語句
1) if函數
語法:if(條件,值1,值2)
功能:實現雙分支
應用在begin end中或外面
2) if結構
# 如果expression為true 執行 statements
IF expression THEN
statements;
END IF; # 有IF一定要有 END IF
# 如果expression為true 執行 statements 否則執行else-statements
IF expression THEN
statements;
ELSE
else-statements;
END IF;
# 不說了。
IF expression THEN
statements;
ELSEIF elseif-expression THEN
elseif-statements;
...
ELSE
else-statements;
END IF;
重點
:IF結構最后都需要END IF
;結尾。
3)示例
DELIMITER $
CREATE PROCEDURE test_if(score FLOAT)
BEGIN
DECLARE ch CHAR DEFAULT 'A';
IF score>90 THEN SET ch='A';
ELSEIF score>80 THEN SET ch='B';
ELSEIF score>60 THEN SET ch='C';
ELSE SET ch='D';
END IF;
select ch;
END $
call test_if(87)
#輸出 B
2.case結構
1、語法
#情況1:類似於switch
case 變量或表達式
when 值1 then 語句1;
when 值2 then 語句2;
...
else 語句n;
end
#情況2:
case
when 條件1 then 語句1;
when 條件2 then 語句2;
...
else 語句n;
end
#應用在begin end 中或外面
2、示例
DELIMITER $
CREATE PROCEDURE test_case(in score FLOAT)
BEGIN
DECLARE ch CHAR DEFAULT 'A';
CASE
WHEN score>90 THEN SET ch='A';
WHEN score>80 THEN SET ch='B';
WHEN score>60 THEN SET ch='C';
ELSE SET ch='D';
END CASE;
select ch;
END $
call test_case(56)$
# 輸出 D
五、循環結構
對於java循環結構有:for、while、do-while。而對於mysql則有:while、loop、repeat
。
還有很重要的一點,對於java跳出循環有:continue 和 break。對於mysql也有自己跳出循環命令。
iterate: 類似於 continue,繼續,結束本次循環,繼續下一次
leave: 類似於 break,跳出,結束當前所在的循環
# 至於它們怎么用,下面會舉例說明
1.while
特點
:先判斷后執行。(相當於java中while)
1)語法
【標簽:】while 循環條件 do
循環體;
end while【 標簽】;
# 當你需要用到 iterate 或者 leave 時就需要用到標簽。如果不需要用到這兩個那么可以不需要標簽
2)示例
#案例:1+2+...100
DELIMITER $
drop procedure if exists `pro_while1` $
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE total INT DEFAULT 0;
DECLARE i INT DEFAULT 1;
WHILE i<=insertCount DO
set total:=total+i;
SET i=i+1;
END WHILE;
select total;
END $
# 輸出:5050
CALL pro_while1(100)$
3)帶有leave語句示例
#案例:1+2+...100
DELIMITER $
drop procedure if exists `pro_while1` $
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE total INT DEFAULT 0;
DECLARE i INT DEFAULT 1;
a:WHILE i<=insertCount DO
IF i=11 THEN LEAVE a; #當i=11是跳出循環 這里就需要用到標簽了
END IF;
set total:=total+i;
SET i=i+1;
END WHILE a;
select total;
END $
# 輸出:55
CALL pro_while1(100)$
這里就用到標簽
(這里為a)了。
2、repeat
1) 語法
特點
:先執行后判斷。(相當於Do-while)
【標簽:】repeat
循環體;
until 結束循環的條件
end repeat 【標簽】;
2)示例
#案例:1+2+...100
DELIMITER $
drop procedure if exists `pro_while1` $
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE total INT DEFAULT 0;
DECLARE i INT DEFAULT 1;
repeat
set total:=total+i;
SET i=i+1;
until i=10 #這里不需要分號
END repeat;
select total;
END $
# 輸出:45
CALL pro_while1(100)$
3、loop
特點
:簡單死循環。(相當於while(true))
1)語法
【標簽:】loop
循環體;
end loop 【標簽】;
2) 示例
#案例:1+2+...100
DELIMITER $
drop procedure if exists `pro_while1` $
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE total INT DEFAULT 0;
DECLARE i INT DEFAULT 1;
a:loop
IF i=11 THEN
LEAVE a;
END IF;
set total:=total+i;
SET i=i+1;
END loop a;
select total;
END $
# 輸出:55
CALL pro_while1(100)$
注意
: 有while一定要有 end while。有repeat一定要有end repeat。有loop一定要有end loop。
只要自己變優秀了,其他的事情才會跟着好起來(少將9)