MySQL資料庫-儲存過程詳解
儲存過程簡單來說,就是為以後的使用而儲存的一條或多條MySQL語句的集合。可將其視為批件,雖然它們的作用不僅限於批處理。在我看來, 儲存過程就是有業務邏輯和流程的集合, 可以在儲存過程中建立表,更新資料, 刪除等等。
MySQL基礎教程之儲存過程
儲存過程簡單來說,就是為以後的使用而儲存的一條或多條MySQL語句的集合。可將其視為批件,雖然它們的作用不僅限於批處理。在我看來, 儲存過程就是有業務邏輯和流程的集合, 可以在儲存過程中建立表,更新資料, 刪除等等。
為什麼要使用儲存過程
- 通過把處理封裝在容易使用的單元中,簡化複雜的操作(正如前面例子所述)。
- 由於不要求反覆建立一系列處理步驟,這保證了資料的完整性。如果所有開發人員和應用程式都使用同一(試驗和測試)儲存過程,則所使用的程式碼都是相同的。這一點的延伸就是防止錯誤。需要執行的步驟越多,出錯的可能性就越大。防止錯誤保證了資料的一致性。
- 簡化對變動的管理。如果表名、列名或業務邏輯(或別的內容)有變化,只需要更改儲存過程的程式碼。使用它的人員甚至不需要知道這些變化。
一個簡單的儲存過程
- createprocedure porcedureName ()
- begin
- selectnamefromuser;
- end;
儲存過程用create procedure 建立, 業務邏輯和sql寫在begin和end之間。mysql中可用call porcedureName ();來呼叫過程。
- -- 呼叫過程
- call porcedureName ();
該儲存過程沒有引數, 只是在呼叫的時候查詢了使用者表的使用者名稱而已, 呼叫結果如下
name |
admin |
admin1 |
admin2 |
admin3 |
刪除儲存過程
- DROPPROCEDURE IF EXISTS porcedureName; -- 沒有括號()
在這裡,我們還要了解三個特別的欄位in,out以及inout的區別,那麼我們可以從下面的例子去體會,然後再看詳細的使用方式:
1.引數in的使用(代表輸入,意思說你的引數要傳到存過過程的過程裡面去) //為了避免儲存過程中分號(";")結束語句,我們使用分隔符告訴mysql直譯器,該段命令是否已經結束了。 /** 案例功能:求1-n的和 */ delimiter $ create procedure p1(in n int) begin declare total int default 0; declare num int default 0; while num < n do set num:=num+1; set total:=total+num; end while; select total; end$call p1(10)$
建立並執行完儲存過程,執行結果如下:
2.引數out的使用(代表往外輸出) //這裡還要注意一點的就是我們的輸出引數一定要設定相應型別的初始,否則不管你怎麼計算得出的結果都為NULL值 /** 案例功能:求1-n的和 */ create procedure p2(in n int,out total int) begin declare num int default 0; set total:=0; while num < n do set num:=num+1; set total:=total+num; end while; end$ 注意:對於第一個輸入引數我們可以理解,但是第二個輸出引數我們到底應該怎麼輸? 這裡我們需要對第二個引數定義一個變數名(更形象點就是你輸入一個輸入型別的引數n,由輸出引數total往外發射輸出我們只需要定義一個變數名來接收這個輸出值即可) call p2(100,@sum)$//這裡的@sum就是我定義用來接收處處total的值 select @sum$ 建立並執行完儲存過程(查詢定義的變數值),執行結果如下:
總結in、out區別: in:表示輸入一個值,你需要一個值,我給你一個值 out:你往外輸出一個值,你輸出的那個值我就拿一個變數來接收你給我輸出的那個值 3.引數inout的使用(既能輸入一個值又能傳出來一個值) /** 功能:傳一個年齡,自動讓年齡增長10歲 */ create procedure p3(inout age int) begin set age:=age+10; end$ 注意:呼叫的時候,我這裡需要和大家宣告一下,inout型的引數值既是輸入型別又是輸出型別,你給它一個值,值不是變數,不是變數那out的時候它怎麼賦給這個值是不是? 因此我們需要先設定一個變數並初始化這個值,呼叫的時候直接傳這個變數即可。 set @currentAge=8$ call p3(@currentAge)$ select @currentAge$ 建立並執行完儲存過程,執行結果如下:
使用引數的儲存過程(備註:decimal(8,2)意思就是總共有8位,小數點後留兩位)
- createprocedure procedureName(
- outmindecimal(8,2),
- outavgdecimal(8,2),
- outmaxdecimal(8,2)
- )
- BEGIN
- selectMIN(price) INTOminfromorder;
- selectAVG(price) intoavgfromorder;
- selectMAX(price) intomaxfromorder;
- END;
此過程接受三個引數, 分別用於獲取訂單表的最小、平均、最大價格。每個引數必須具有指定的類
型,這裡使用十進位制值(decimal(8,2)), 關鍵字OUT指出相應的引數用來從儲存過程傳出
一個值(返回給呼叫者)
MySQL支援IN(傳遞給儲存過程)、OUT(從儲存過程傳出,如這裡所用)和INOUT(對儲存過程傳入和傳出)型別的引數。儲存過程的程式碼位於BEGIN和END語句內,如前所見,它們是一系列SELECT語句,用來檢索值,然後儲存到相應的變數(通過指定INTO關鍵字)
為呼叫此修改過的儲存過程,必須指定3個變數名,如下所示:(所有MySQL變數都必須以@開始。)
- -- 由於過程指定三個引數, 故呼叫必須要引數匹配
- call procedureName(@min, @avg, @max);
該呼叫並沒有任何輸出, 只是把呼叫的結果賦給了呼叫時傳入的變數(@min, @avg, @max)。然後即可呼叫顯示該變數的值。
- select @min, @avg, @max;
結果如下
@min | @avg | @max |
42.00 | 601.00 | 2222.00 |
使用in引數, 輸入一個使用者id, 返回該使用者所有訂單的總價格。
- createprocedure getTotalById (
- in userId int,
- out total decimal(8,2)
- )
- BEGIN
- selectSUM(r.price) fromorder r
- where r.u_id = userId
- into total;
- END;
呼叫儲存過程
- call getTotalById(1, @total);
- select @total;
結果將返回該使用者所有訂單的合計價格。
複雜一點的過程, 根據使用者id獲取該使用者的所有訂單價格, 並動態的選擇是否加稅。程式碼設計如下
- createprocedure getTotalByUser2(
- in userId int,
- in flag boolean, -- 是否加稅標記
- out total decimal(8,2)
- )
- begin
- DECLARE tmptotal DECIMAL(8,2);
- DECLARE taxrate intDEFAULT 6;-- 預設的加稅的利率
- selectSUM(r.price) fromorder r
- where r.u_id = userId
- into tmptotal;
- if flag then
- select tmptotal + (tmptotal/1000*taxrate) into tmptotal;
- end if;
- select tmptotal into total;
- END;
該過程傳入三個引數, 使用者id, 是否加稅以及返回的總價格,在過程內部, 定義兩個區域性變數tmptotal和taxrate,把查詢出來的結果賦給臨時變數, 在判斷是否加稅。最後把區域性變數的值賦給輸出引數。
- call getTotalByUser2(1, false, @total); -- 不加稅
- call getTotalByUser2(1, true, @total); -- 加稅
- select @total;