数据库存储过程讲解与实例
目錄
1 存儲過程簡介
2 存儲過程使用
2.1?創(chuàng)建存儲過程
2.2 in,out以及inout
1 存儲過程簡介
?SQL語句需要先編譯然后執(zhí)行,而存儲過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經(jīng)編譯后存儲在數(shù)據(jù)庫中,用戶通過指定存儲過程的名字并給定參數(shù)(如果該存儲過程帶有參數(shù))來調(diào)用執(zhí)行它。
????存儲過程是可編程的函數(shù),在數(shù)據(jù)庫中創(chuàng)建并保存,可以由SQL語句和控制結(jié)構(gòu)組成。當(dāng)想要在不同的應(yīng)用程序或平臺上執(zhí)行相同的函數(shù),或者封裝特定功能時(shí),存儲過程是非常有用的。數(shù)據(jù)庫中的存儲過程可以看做是對編程中面向?qū)ο蠓椒ǖ哪M,它允許控制數(shù)據(jù)的訪問方式。
優(yōu)點(diǎn)
- 存儲過程可封裝,并隱藏復(fù)雜的商業(yè)邏輯。
- 存儲過程可以回傳值,并可以接受參數(shù)。
- 存儲過程無法使用 SELECT 指令來運(yùn)行,因?yàn)樗亲映绦?#xff0c;與查看表,數(shù)據(jù)表或用戶定義函數(shù)不同。
- 存儲過程可以用在數(shù)據(jù)檢驗(yàn),強(qiáng)制實(shí)行商業(yè)邏輯等。
缺點(diǎn)
- 存儲過程,往往定制化于特定的數(shù)據(jù)庫上,因?yàn)橹С值木幊陶Z言不同。當(dāng)切換到其他廠商的數(shù)據(jù)庫系統(tǒng)時(shí),需要重寫原有的存儲過程。
- 存儲過程的性能調(diào)校與撰寫,受限于各種數(shù)據(jù)庫系統(tǒng)。
2 存儲過程使用
存儲過程的一些基本語法:
--------------創(chuàng)建存儲過程-----------------CREATE PROC [ EDURE ] procedure_name [ ; number ][ { @parameter data_type }[ VARYING ] [ = default ] [ OUTPUT ]] [ ,...n ][ WITH{ RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ][ FOR REPLICATION ]AS sql_statement [ ...n ]--------------調(diào)用存儲過程-----------------EXECUTE Procedure_name '' --存儲過程如果有參數(shù),后面加參數(shù)格式為:@參數(shù)名=value,也可直接為參數(shù)值value--------------刪除存儲過程-----------------drop procedure procedure_name --在存儲過程中能調(diào)用另外一個(gè)存儲過程,而不能刪除另外一個(gè)存儲過程創(chuàng)建存儲過程的參數(shù):
1.procedure_name?:存儲過程的名稱,在前面加#為局部臨時(shí)存儲過程,加##為全局臨時(shí)存儲過程。
2.; number:是可選的整數(shù),用來對同名的過程分組,以便用一條 DROP PROCEDURE 語句即可將同組的過程一起除去。例如,名為 orders 的應(yīng)用程序使用的過程可以命名為 orderproc;1、orderproc;2 等。DROP PROCEDURE orderproc 語句將除去整個(gè)組。如果名稱中包含定界標(biāo)識符,則數(shù)字不應(yīng)包含在標(biāo)識符中,只應(yīng)在 procedure_name 前后使用適當(dāng)?shù)亩ń绶?
3.@parameter: 存儲過程的參數(shù)。可以有一個(gè)或多個(gè)。用戶必須在執(zhí)行過程時(shí)提供每個(gè)所聲明參數(shù)的值(除非定義了該參數(shù)的默認(rèn)值)。存儲過程最多可以有 2.100 個(gè)參數(shù)。?
使用 @ 符號作為第一個(gè)字符來指定參數(shù)名稱。參數(shù)名稱必須符合標(biāo)識符的規(guī)則。每個(gè)過程的參數(shù)僅用于該過程本身;相同的參數(shù)名稱可以用在其它過程中。默認(rèn)情況下,參數(shù)只能代替常量,而不能用于代替表名、列名或其它數(shù)據(jù)庫對象的名稱。有關(guān)更多信息,請參見 EXECUTE。?
4.data_type:參數(shù)的數(shù)據(jù)類型。所有數(shù)據(jù)類型(包括 text、ntext 和 image)均可以用作存儲過程的參數(shù)。不過,cursor 數(shù)據(jù)類型只能用于 OUTPUT 參數(shù)。如果指定的數(shù)據(jù)類型為 cursor,也必須同時(shí)指定 VARYING 和 OUTPUT 關(guān)鍵字。有關(guān) SQL Server 提供的數(shù)據(jù)類型及其語法的更多信息,請參見數(shù)據(jù)類型。?
說明 對于可以是 cursor 數(shù)據(jù)類型的輸出參數(shù),沒有最大數(shù)目的限制。?
5.VARYING:?指定作為輸出參數(shù)支持的結(jié)果集(由存儲過程動態(tài)構(gòu)造,內(nèi)容可以變化)。僅適用于游標(biāo)參數(shù)。?
6.default:?參數(shù)的默認(rèn)值。如果定義了默認(rèn)值,不必指定該參數(shù)的值即可執(zhí)行過程。默認(rèn)值必須是常量或 NULL。如果過程將對該參數(shù)使用 LIKE 關(guān)鍵字,那么默認(rèn)值中可以包含通配符(%、_、[] 和 [^])。
7.OUTPUT?:表明參數(shù)是返回參數(shù)。該選項(xiàng)的值可以返回給 EXEC[UTE]。使用 OUTPUT 參數(shù)可將信息返回給調(diào)用過程。Text、ntext 和 image 參數(shù)可用作 OUTPUT 參數(shù)。使用 OUTPUT 關(guān)鍵字的輸出參數(shù)可以是游標(biāo)占位符。?
8.RECOMPILE:?表明 SQL Server 不會緩存該過程的計(jì)劃,該過程將在運(yùn)行時(shí)重新編譯。在使用非典型值或臨時(shí)值而不希望覆蓋緩存在內(nèi)存中的執(zhí)行計(jì)劃時(shí),請使用 RECOMPILE 選項(xiàng)。
9.ENCRYPTION:?表示 SQL Server 加密 syscomments 表中包含 CREATE PROCEDURE 語句文本的條目。使用 ENCRYPTION 可防止將過程作為 SQL Server 復(fù)制的一部分發(fā)布。 說明 在升級過程中,SQL Server 利用存儲在 syscomments 中的加密注釋來重新創(chuàng)建加密過程。?
10.FOR REPLICATION?:指定不能在訂閱服務(wù)器上執(zhí)行為復(fù)制創(chuàng)建的存儲過程。.使用 FOR REPLICATION 選項(xiàng)創(chuàng)建的存儲過程可用作存儲過程篩選,且只能在復(fù)制過程中執(zhí)行。本選項(xiàng)不能和 WITH RECOMPILE 選項(xiàng)一起使用。?
11.AS?:指定過程要執(zhí)行的操作。
12.sql_statement?:過程中要包含的任意數(shù)目和類型的 Transact-SQL 語句。但有一些限制。
2.1?創(chuàng)建存儲過程
| UserAccount | ||||
| UserID | UserName | PassWord | RegisterTime | RegisterIP |
| 12 | 6 ?????????????????? | 6 ?????????????????? | 2012-12-31 | 6 |
| 18 | 5 ?????????????????? | 5 ?????????????????? | 2013-01-01 | 5 |
| 19 | 1 ?????????????????? | 1 ?????????????????? | 2013-01-01 | 1 |
| 20 | 2 ?????????????????? | 2 ?????????????????? | 2013-01-01 | 2 |
| 21 | 3 ?????????????????? | 3 ?????????????????? | 2013-01-01 | 3 |
| 22 | 4 ?????????????????? | 4 ?????????????????? | 2013-01-01 | 4 |
| 23 | 5 ?????????????????? | 5 ?????????????????? | 2013-01-01 | 5 |
| 25 | 7 ?????????????????? | 7 ?????????????????? | 2013-01-01 | 7 |
| 26 | 8 ?????????????????? | 8 ?????????????????? | 2013-01-01 | 8 |
| NULL | NULL | NULL | NULL | NULL |
針對上面的表,我使用存儲過程對它做一些操作:
1.?只返回單一記錄集的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程---------------- create Procedure GetUserAccount as select * from UserAccount go-------------執(zhí)行上面的存儲過程---------------- exec GetUserAccount?結(jié)果:相當(dāng)于運(yùn)行 select * from?UserAccount?這行代碼,結(jié)果為整個(gè)表的數(shù)據(jù)。
2.沒有輸入輸出的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程----------------create Procedure inUserAccount as insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9) go-------------執(zhí)行上面的存儲過程----------------exec inUserAccount結(jié)果:相當(dāng)于運(yùn)行?insert?into?UserAccount (UserName,[PassWord],RegisterTime,RegisterIP)?values(9,9,'2013-01-02',9)?這行代碼。
3.有返回值的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程----------------create Procedure inUserAccountRe as insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(10,10,'2013-01-02',10) return @@rowcount go-------------執(zhí)行上面的存儲過程----------------exec inUserAccountRe?解釋:這里的@@rowcount為執(zhí)行存儲過程影響的行數(shù),執(zhí)行的結(jié)果是不僅插入了一條數(shù)據(jù),還返回了一個(gè)值即 return value =1 ?,這個(gè)可以在程序中獲取,稍后在c#調(diào)用存儲過程中會有說到。
4.有輸入?yún)?shù)和輸出參數(shù)的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程----------------create Procedure GetUserAccountRe @UserName nchar(20), @UserID int output as if(@UserName>5) select @UserID=COUNT(*) from UserAccount where UserID>25 else set @UserID=1000 go-------------執(zhí)行上面的存儲過程----------------exec GetUserAccountRe '7',null解釋:@UserName為輸入?yún)?shù),@UserID為輸出參數(shù)。?運(yùn)行結(jié)果為@userID為COOUT(*)即 =1。
5. 同時(shí)具有返回值、輸入?yún)?shù)、輸出參數(shù)的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程----------------create Procedure GetUserAccountRe1 @UserName nchar(20), @UserID int output as if(@UserName>5) select @UserID=COUNT(*) from UserAccount where UserID>25 else set @UserID=1000 return @@rowcount go-------------執(zhí)行上面的存儲過程----------------exec GetUserAccountRe1 '7',null結(jié)果:@userID為COOUT(*)即 =1,Retun Value=1。
6.同時(shí)返回參數(shù)和記錄集的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程----------------create Procedure GetUserAccountRe2 @UserName nchar(20), @UserID int output as if(@UserName>5) select @UserID=COUNT(*) from UserAccount where UserID>25 else set @UserID=1000 select * from UserAccount return @@rowcount go-------------執(zhí)行上面的存儲過程----------------exec GetUserAccountRe2 '7',null結(jié)果:返回執(zhí)行?select?*?from?UserAccount 這句代碼的結(jié)果集,同時(shí)@userID為COOUT(*)即 =1,Retun Value=9。?
7.返回多個(gè)記錄集的存儲過程?
-------------創(chuàng)建名為GetUserAccount的存儲過程----------------create Procedure GetUserAccountRe3 as select * from UserAccount select * from UserAccount where UserID>5 go-------------執(zhí)行上面的存儲過程----------------exec GetUserAccountRe3結(jié)果:返回兩個(gè)結(jié)果集,一個(gè)為?select?*?from?UserAccount,另一個(gè)為?select?*?from?UserAccount?where?UserID>5 。
2.2 in,out以及inout
??MySQL存儲過程的參數(shù)用在存儲過程的定義,共有三種參數(shù)類型
????IN,OUT,INOUT
????格式為:Create procedure|function([[IN |OUT |INOUT ] 參數(shù)名 數(shù)據(jù)類形...])
????IN 輸入?yún)?shù)
????????表示該參數(shù)的值必須在調(diào)用存儲過程時(shí)指定,在存儲過程中修改該參數(shù)的值不能被返回,為默認(rèn)值
????OUT 輸出參數(shù)
????????該值可在存儲過程內(nèi)部被改變,并可返回
????INOUT 輸入輸出參數(shù)
????????調(diào)用時(shí)指定,并且可被改變和返回
1.參數(shù)in的使用(代表輸入,意思說你的參數(shù)要傳到存過過程的過程里面去)
//為了避免存儲過程中分號(";")結(jié)束語句,我們使用分隔符告訴mysql解釋器,該段命令是否已經(jīng)結(jié)束了。
/** 案例功能:求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)$創(chuàng)建并執(zhí)行完存儲過程,運(yùn)行結(jié)果如下:
2.參數(shù)out的使用(代表往外輸出)
//這里還要注意一點(diǎn)的就是我們的輸出參數(shù)一定要設(shè)置相應(yīng)類型的初始,否則不管你怎么計(jì)算得出的結(jié)果都為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$注意:對于第一個(gè)輸入?yún)?shù)我們可以理解,但是第二個(gè)輸出參數(shù)我們到底應(yīng)該怎么輸?
這里我們需要對第二個(gè)參數(shù)定義一個(gè)變量名(更形象點(diǎn)就是你輸入一個(gè)輸入類型的參數(shù)n,由輸出參數(shù)total往外發(fā)射輸出我們只需要定義一個(gè)變量名來接收這個(gè)輸出值即可)
call p2(100,@sum)$//這里的@sum就是我定義用來接收處處total的值
select @sum$
創(chuàng)建并執(zhí)行完存儲過程(查詢定義的變量值),運(yùn)行結(jié)果如下:
總結(jié)in、out區(qū)別:
in:表示輸入一個(gè)值,你需要一個(gè)值,我給你一個(gè)值
out:你往外輸出一個(gè)值,你輸出的那個(gè)值我就拿一個(gè)變量來接收你給我輸出的那個(gè)值
3.參數(shù)inout的使用(既能輸入一個(gè)值又能傳出來一個(gè)值)
/** 功能:傳一個(gè)年齡,自動讓年齡增長10歲 */ create procedure p3(inout age int) begin set age:=age+10; end$注意:調(diào)用的時(shí)候,我這里需要和大家聲明一下,inout型的參數(shù)值既是輸入類型又是輸出類型,你給它一個(gè)值,值不是變量,不是變量那out的時(shí)候它怎么賦給這個(gè)值是不是?
因此我們需要先設(shè)置一個(gè)變量并初始化這個(gè)值,調(diào)用的時(shí)候直接傳這個(gè)變量即可。
set @currentAge=8$
call p3(@currentAge)$
select @currentAge$
創(chuàng)建并執(zhí)行完存儲過程,運(yùn)行結(jié)果如下:
使用參數(shù)的存儲過程(備注:decimal(8,2)意思就是總共有8位,小數(shù)點(diǎn)后留兩位)
create?procedure?procedureName(?out?min?decimal(8,2),?out?avg?decimal(8,2),?out?max?decimal(8,2)? )? BEGIN?select?MIN(price)?INTO?min?from?order;?select?AVG(price)?into?avg?from?order;?select?MAX(price)?into?max?from?order;? END;??此過程接受三個(gè)參數(shù), 分別用于獲取訂單表的最小、平均、最大價(jià)格。每個(gè)參數(shù)必須具有指定的類
型,這里使用十進(jìn)制值(decimal(8,2)), 關(guān)鍵字OUT指出相應(yīng)的參數(shù)用來從存儲過程傳出
一個(gè)值(返回給調(diào)用者)
MySQL支持IN(傳遞給存儲過程)、OUT(從存儲過程傳出,如這里所用)和INOUT(對存儲過程傳入和傳出)類型的參數(shù)。存儲過程的代碼位于BEGIN和END語句內(nèi),如前所見,它們是一系列SELECT語句,用來檢索值,然后保存到相應(yīng)的變量(通過指定INTO關(guān)鍵字)
為調(diào)用此修改過的存儲過程,必須指定3個(gè)變量名,如下所示:(所有MySQL變量都必須以@開始。)
?
--?由于過程指定三個(gè)參數(shù),?故調(diào)用必須要參數(shù)匹配? call?procedureName(@min,?@avg,?@max);??該調(diào)用并沒有任何輸出, 只是把調(diào)用的結(jié)果賦給了調(diào)用時(shí)傳入的變量(@min, @avg, @max)。然后即可調(diào)用顯示該變量的值。
select?@min,?@avg,?@max;?結(jié)果如下
| @min | @avg | @max |
| 42.00 | 601.00 | 2222.00 |
使用in參數(shù), 輸入一個(gè)用戶id, 返回該用戶所有訂單的總價(jià)格。
create?procedure?getTotalById?(?in?userId?int,?out?total?decimal(8,2)? )? BEGIN?select?SUM(r.price)?from?order?r?where?r.u_id?=?userId?into?total;? END;??調(diào)用存儲過程
?
call?getTotalById(1,?@total);?select?@total;??結(jié)果將返回該用戶所有訂單的合計(jì)價(jià)格。
復(fù)雜一點(diǎn)的過程, 根據(jù)用戶id獲取該用戶的所有訂單價(jià)格, 并動態(tài)的選擇是否加稅。代碼設(shè)計(jì)如下
?
create?procedure?getTotalByUser2(?in?userId?int,?in?flag?boolean,?--?是否加稅標(biāo)記?out?total?decimal(8,2)? )? begin?DECLARE?tmptotal?DECIMAL(8,2);?DECLARE?taxrate?int?DEFAULT?6;--?默認(rèn)的加稅的利率?select?SUM(r.price)?from?order?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;??該過程傳入三個(gè)參數(shù), 用戶id, 是否加稅以及返回的總價(jià)格,在過程內(nèi)部, 定義兩個(gè)局部變量tmptotal和taxrate,把查詢出來的結(jié)果賦給臨時(shí)變量, 在判斷是否加稅。最后把局部變量的值賦給輸出參數(shù)。
?
call?getTotalByUser2(1,?false,?@total);?--?不加稅? call?getTotalByUser2(1,?true,?@total);??--?加稅? select?@total;??
?
總結(jié)
以上是生活随笔為你收集整理的数据库存储过程讲解与实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机一级考试基本操作是什么,计算机一级
- 下一篇: 笔记(数据库)