一個存儲過程是一個可編程的函數,它能夠在MySQL中建立並保存。它是由一些SQL語句和一些特殊的控制結構語句組成。
sql
當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定的功能時,存儲過程是一個很是有用的方式。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。數據庫
基本示例total_ordres編程
delimiter // create procedure total_orders (out total float) BEGIN select sum(amount) into total from orders; END // delimiter ;
下面,讓咱們來逐行分析以上代碼:數組
第一行語句:ide
delimiter //
將語句末尾的分隔符從默認值(MySQL的默認分隔符爲 ; )改變爲// 。這樣作的目的是能夠在存儲過程當中使用分號分隔符,這樣MySQL就會將分號做爲存儲過程的代碼,從而不會當即執行。函數
接下來的語句:oop
create procedure total_ordres (out total float)
定義一個存儲過程。該存儲過程的名稱是 total_orders ,它只有一個total參數,該參數是最後獲得結果的值。out表示該參數將被 傳出 或 返回。這裏也能夠聲明爲 in ,表示該值必須傳入到存儲過程當中。或者 inout 表示該值必須傳入可是能夠被存儲過程修改。fetch
float 表示參數的類型。this
若是但願使用多個參數,能夠提供一個由逗號間隔的參數列表,就像在PHP中同樣。 過程體必須封裝在BEGIN END 語句中。spa
在聲明瞭過程後,能夠將分隔符從新設置爲分號:
delimiter ;
在過程聲明瞭以後,能夠用call 關鍵字調用該過程:
call total_orders(@h);
這個語句將調用total_orders 過程,而且傳入一個用來保存結果的變量。
要查看該變量,以下語句所示:
select @h ;
函數
與建立過程的方法相似,還能夠建立一個函數。函數接收輸入參數而且返回一個惟一值。建立函數的基本語法幾乎相同。
delimiter // create function add_tax (price float) retuns float return price*1.1 ; delimiter ;
能夠看到,該示例使用了function關鍵字。而不是以前的procedure 關鍵字。此外,兩者還存在一些其餘差別。
參數沒必要經過IN 或 OUT來指定,由於在函數中全部參數都是IN 或輸入參數。在參數列表以後是returns float子句,它指定了返回值的類型。須要再次提到的是,該值能夠是任何有效的MySQL類型。
使用return 語句能夠返回一個值,就像PHP中所介紹的同樣。
請注意,這個示例中並無使用BEGIN 和 END語句。固然可使用它們,可是它們並非必需的。就像PHP中,若是一個語句塊只包含了一個語句,那麼該語句塊的開始和結束標記能夠省略。
調用函數 與 調用過程 存在一些差別。能夠調用內置函數的相同方式調用一個存儲函數。
select add_tax(100);
該語句的返回以下所示:
+-------------------+
| add_tax(100) |
+-------------------+
| 110 |
+-------------------+
在定義了存儲過程 和 存儲函數以後,可使用以下所示的語句來查看定義這些過程和函數的代碼:
show create procedure total_orders; 或者 show create function add_tax;
也可使用以下語句來刪除它們:
drop procedure total_orders; 或者 drop function add_tax;
存儲過程提供了使用控制結構、變量、DECLARE句柄(就像異常)的功能,以及遊標這個重要概念。
在接下來的文章中,咱們將簡單介紹這些概念。
局部變量
使用declare語句,能夠在BEGIN ... END語句塊中聲明局部變量。
例如,能夠對add_tax函數進行修改,使其使用一個局部變量來保存稅率。
示例:
delimiter // create function add_tax (price float) returns float begin declare tax float default 0.10; return price*(1+tax); end // delimiter ;
正如你看到的,咱們使用了declare關鍵字以及變量名稱和變量類型聲明瞭該局部變量。
default子句是可選的,它指定了該變量的初始值。如今能夠開始使用這個變量了。
遊標 和 控制結構
如今,讓咱們來分析一個更復雜的例子。在這個例子中,咱們將編寫一個存儲過程,該存儲過程將計算出最大金額的訂單,而且返回該訂單的orderid(很明顯,這能夠經過一個簡單的查詢就能夠得出結果,可是這個簡單的示例只是爲了說明如何使用遊標 和 控制結構)。
代碼以下:
delimiter // create procedure largest_order (out largest_id int) begin declare this_id int; declare this_amount float; declare l_amount float default 0.0; declare l_id int; declare done int default 0; declare c1 cursor for select orderid, amount from orders; declare continue handle for sqlstate '02000' set done = 1 ; open c1 ; repeat fetch c1 into this_id , this_amount ; if not done then if this_amount > l_amount then set l_amount = this_amount ; set l_id = this_id ; end if; end if; until done end repear; close c1 ; set largest_id = l_id ; end // delimiter ;
以上代碼使用了控制語句(條件語句和循環語句)、遊標 和 聲明句柄。下面咱們逐行分析以上代碼。
this_id 和 this_amount變量保存了當前行orderid 和 amount值。 l_amount 和 l_id 變量用來存儲最大的訂單金額和與之對應的ID。
下一個變量被聲明爲done ,初始化爲0 。這個變量是循環標記。當遍歷了全部須要查看的行,能夠將該變量設置爲1 (True)。
declare continue handle for sqlstate '02000' set done = 1 ;
是一個聲明句柄。它相似於存儲過程當中的一個異常。在continue句柄和 exit句柄中,也可使用它。就像以上代碼所顯示的,continue 句柄執行了指定的動做,而且繼續存儲過程的執行。 exit句柄將從最近的begin...end代碼中退出。
聲明句柄的下一個部分指定了句柄被調用的時間。在這個例子中,該句柄將在sqlstate '02000' 語句被執行時調用。 你可能會奇怪,這是個什麼意思,由於該語句很是神祕。這意味着,該句柄將在沒法再獲得記錄行以後被調用。咱們將逐行處理一個結果集,並且當遍歷了全部須要處理的記錄時,這個句柄纔會被調用。 也能夠指定等價的 FOR NOT FOUND語句。其餘選項還包括SQLWARNING 和 SQLEXCEPTION 。
接下來就是遊標。一個遊標相似於一個數組;它將從一個查詢中得到結果集,而且容許一次只處理一行。分析如下游標:
declare c1 cursor for select orderid, amount from orders ;
這個遊標名稱爲 c1 。它只是將要保存內容的定義。該查詢還不會被執行。
接下來一行代碼:
open c1 ;
真正運行這個查詢。要得到每個數據行,必須運行一個 fetch 語句。能夠在repeat 循環中完成此操做。
在這個例子中,循環語句以下所示:
repeat .... until done end repeat ;
請注意,只有在循環語句塊的末尾纔會檢查循環條件。
存儲過程還支持while 循環,以下所示:
while condition do .... end while
此外,還支持loop循環語句,以下所示:
loop .... end loop
這些循環沒有內置的循環條件,可是能夠經過 leave 語句退出循環。
請注意,存儲過程不支持 for 循環。
繼續這個例子,一下代碼將得到一個數據行:
fetch c1 into thid_id, this_amount ;
以上代碼將從遊標查詢中得到一個數據行。該查詢所得到的兩個屬性保存在兩個指定的局部變量中。
咱們能夠檢查一個數據航是否被得到,而後再將當前循環量與最大的存儲值進行比較,經過兩個 if 語句的方式,以下所示:
if not done then if this_amount > l_amount then set l_amount = this_amount ; set l_id = this_id ; end if ; end if ;
請注意,變量值將經過set 語句進行設置。
除了if ... then 語句外,存儲過程還支持 if ... then ... else 語句結構。以下所示:
if condition then ... [elseif condition then] ... [else] ... end if
此外,也可使用case語句,以下形式所示:
case value when value then statement [when value then statement ... ] [else statement] end case
回到這個例子,在循環語句末尾,將執行一些清除操做:
close c1 ; set largest_id = l_id ;
close語句將關閉這個遊標。
最後,將全部計算出的最大值賦值給 OUT 參數。不能將該參數做爲臨時變量,只能用來保存最終值。
若是按照以上方式建立了這個存儲過程,能夠像調用其餘存儲過程同樣調用這個存儲過程:
call largest_order (@k) ; select @k ;
將得到相似於以下所示的輸出:
+--------+
| @k |
+--------+
| 3 |
+--------+
你能夠本身檢查計算結果是否正確。