大綱:
- 創建、刪除、調用。
- 聲明變量、變量賦值、存儲過程的入參
- 聲明游標
- 聲明異常處理器
- 判斷
- 循環
- 使用心得
- mybatis調用存儲過程
一、創建、刪除、調用
- 創建
DELIMITER $$ #修改分隔符 CREATE PROCEDURE test(IN pname VARCHAR(50)) #括號里是入參。 BEGIN select pname; #存儲過程中的語句用;結尾 END$$ #存儲過程本身用修改后的分隔符$$結尾 DELIMITER ; ##還原分隔符
begin、end之間是存儲的執行的代碼塊。
tips:mysql不支持匿名塊(沒有create procedure,直接寫begin、end之間的內容),因此msql的代碼塊只能放在存儲過程,自定義函數,觸發器中。
- 刪除
DROP PROCEDURE IF EXISTS test; #存儲過程
和表一樣建立前確保數據庫中沒有同名存儲過程。
- 調用
CALL test('xx');
調用用call命令、這里參數傳一個字符串進去、調用后顯示xx。
二、聲明變量、變量賦值、存儲過程的入參
- declare聲明變量
- set是直接賦值(可以用 '=' 號賦值,也可以用 ':=' 賦值,本文例子中都是用 '=' 賦值的。但之后的學習中發現用這種 ':=' 方式賦值更規范一些。)
- select是將查詢的結果進行賦值
DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test(IN pname VARCHAR(50)) BEGIN DECLARE prefix VARCHAR(20); #聲明變量 set prefix = 'nihao:'; #select 'nihenhao:' into prefix; 賦值 select concat(prefix,pname); #concat函數:拼接2個字符串 END$$ DELIMITER ; CALL test('xx');:賦值方式有2種、根據需求選擇。
- 創建存儲過程的時候已經提到了,存儲過程可以有入參IN,也可以有出參OUT,還可以有出入參INOUT。IN類型只能作為傳入參數使用,OUT只能作為傳出參數使用,只有INOUT既可以傳入存儲過程又能傳出來。
drop PROCEDURE test; DELIMITER $$ CREATE PROCEDURE test( IN people VARCHAR(8), OUT name VARCHAR(8),INOUT age INT ) BEGIN IF people = 'man' THEN SET name := 'xiaoming'; SET age :=age+1; ELSE SET name := 'xiaohong'; SET age :=age+10; END IF; END $$ set @people = 'man'; #@var_name這樣的寫法是聲明一個用戶變量,只有在本次連接的客戶端中有效。這里聲明了3個變量people、name、age set @name = null; set @age = 6; call test(@people,@name,@age); SELECT @people,@name,@age from dual; #結果:man xiaoming 7
三、聲明游標
- 准備一個測試表
TRUNCATE names; create table names ( name VARCHAR(20), age int ); INSERT into names VALUES ('lby',45); INSERT into names VALUES ('lala',23);
- 游標可以理解為是一個帶指針的結果集。
DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test() BEGIN DECLARE name VARCHAR(20); DECLARE age int; DECLARE temp VARCHAR(50); DECLARE c1 CURSOR FOR select * from names; #聲明游標 OPEN c1; #使用游標前打開游標 FETCH c1 INTO name,age; #將游標中的第一行依次付給name,age(name=lby,age=45)。tips:游標列數和變量數要相同。 set temp = CONCAT(name,age); FETCH c1 INTO name,age; #第一次fetch后指針下移動,賦值第二行給name,age(name=lala,age=23)。 CLOSE c1; #使用游標后關閉游標 set temp = CONCAT(temp,CONCAT(name,age)); SELECT temp from dual; #lby45lala23 END$$ DELIMITER ; CALL test();
四、聲明異常處理器
- 當sql執行時報錯時會報出相應的sqlstate,根據不同的sqlstate我們可以給出不同的處理。--附一個sqlstate的詳解:blog.csdn.net/u014653854/article/details/78986780
- 處理器有2種:exit、continue。
TRUNCATE names; #清空names表使fetch報錯SQLSTATE'02000' DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test() BEGIN declare age int default 0 ; declare name VARCHAR(20) default 0 ; declare flag int default 0; DECLARE c1 CURSOR FOR select * from names; declare CONTINUE HANDLER FOR SQLSTATE '02000' SET flag = 111; # continue handler 檢測報錯為02000的時候 將flag設為111,存儲過程繼續執行,如果換為exit handler在行為完處理語句set flag=111后直接退出存儲過程。 OPEN c1; FETCH c1 into name,age; #當執行這句時會報錯sqlstate:02000 ,continue handler觸發set flag= 111,繼續執行后面的代碼。 CLOSE c1; select flag; #111 END$$ DELIMITER ; CALL ifpay_ccpay.test();
五、判斷
- if判斷
DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test(in age int) BEGIN declare flag VARCHAR(20); IF age = 1 THEN SET flag = '一'; ELSEIF age = 2 THEN SET flag = '二'; ELSE SET flag = 'I DONT KNOW'; END IF; #結束標志 select flag; #二 END$$ DELIMITER ; CALL ifpay_ccpay.test(2);
六、循環
循環有三種
- while循環
DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test() BEGIN DECLARE age int DEFAULT 0; mywhile: WHILE age < 5 #條件, DO set age = age+1; #do與endwhile之間是循環內容 END WHILE ; SELECT age; #5 END$$ DELIMITER ; CALL test();
- repeat循環
DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test() BEGIN DECLARE age int DEFAULT 0; mywhile: repeat set age = age+1; #循環體 UNTIL age>3 END REPEAT ; #條件 SELECT age; #4 END$$ DELIMITER ; CALL test();
- loop循環
DROP PROCEDURE IF EXISTS test; DELIMITER $$ CREATE PROCEDURE test() myproc: #存儲過程的label BEGIN DECLARE age int DEFAULT 0; DECLARE count int DEFAULT 10; myloop: #loop的label LOOP set age = age +1; IF age < 5 then ITERATE myloop; #忽略后面代碼繼續執行。(continue) END IF; set count = count - 1; SELECT 'haha'; LEAVE myloop; #離開循環。(break) leave也可直接用於存儲過程本身myproc,如果這里換成myproc,則顯示haha END LOOP; SELECT age,count; #5 9 END$$ DELIMITER ; CALL test();
代碼中有3個概念:label、iterate、leave
label:名稱標簽,while、repeat、loop循環或者 存儲過程本身begin關鍵字前面都可以加一個名稱標簽。
iterate:用於循環、繼續當前循環,相當於java循環中的continue。
leave:1.用於循環、離開當前循環,相當於java循環中的break。
2.也可用於存過過程本身,直接離開存過過程。
循環小結:1.while repeat區別在於:while 先判斷循環條件再循環,repeat 線循環后判斷。
2.loop沒有結束條件,需要手動退出。
3.iterate、leave也可以用於while、repeat。
七、使用心得
- 存儲過程中慎用delete語句。
- 存儲過程適合一些有規律的數據操作,比如根據一些業務規則初始化一些數據。
- 盡量不要用它代替簡單的業務sql,因為存儲過程的維護、遷移、易讀性都不如直接寫在代碼中好。
八、mybatis調用存儲過程
調用方式參考我另一篇文章:mybatis調用存儲過程