存儲過程

存儲過程優(yōu)點

運行T-SQL語句進行編程有兩種辦法道逗,一種是把T-SQL語句全部寫在應用程序中,并存儲在本地;另一種是把部分T-SQL語句編寫的程序作為存儲過程存儲在SQL Server中,只有本地的應用程序調用存儲過程树叽。大多數程序員偏向使用后者,原因在于存儲過程具有以下優(yōu)點:

  • 一次編譯曼追,多次執(zhí)行玄糟。第一次執(zhí)行某個過程時,將編譯該過程以確定檢索數據的最優(yōu)訪問計劃。 如果已經生成的計劃仍保留在數據庫引擎計劃緩存中,則該過程隨后執(zhí)行的操作可能重新使用該計劃。
  • 可在應用程序中多次調用预侯;修改存儲過程不會影響應用程序源代碼。
  • 存儲過程存儲在服務中峰锁,能夠減少網絡流量萎馅。比如一個需要數百行T-SQL代碼的操作可以通過一條執(zhí)行存儲過程代碼的語句來調用,而不需要在網絡中發(fā)送數百行代碼虹蒋。
  • 存儲過程可被作為一種安全機制來充分利用糜芳。可以只授予用戶執(zhí)行存儲過程的權限魄衅,而不授予用戶直接訪問存儲過程中涉及的表的權限峭竣。這樣,用戶只能通過存儲過程來訪問表晃虫,并進行有限的操作皆撩,從而保證了表中數據的安全。使用授權操作設置各個用戶的權限哲银。

存儲過程分類

(1)系統(tǒng)存儲過程
??SQL Server提供的存儲過程扛吞,用于執(zhí)行與系統(tǒng)相關的任務,主要存儲在master數據庫并以sp_為前綴荆责,例如sp_addtype滥比、sp_rename等。

(2)擴展存儲過程
??擴展存儲過程是以在SQL Server環(huán)境之外執(zhí)行的動態(tài)鏈接庫(Dymatic-Link)Libraries,DDL)來實現的做院,執(zhí)行系統(tǒng)存儲過程不能勝任的任務盲泛,如發(fā)郵件、文件處理等键耕,通常以前綴xp_開頭寺滚。執(zhí)行擴展存儲過程的方式與存儲過程的相似。

(3)臨時存儲過程
??臨時存儲過程首先是本地存儲過程屈雄。SQL Server支持兩種臨時存儲過程:局部臨時過程和全局臨時過程玛迄。
??如果存儲過程的前面有一個符號“#”,那么它就是局部臨時過程棚亩,只能在一個用戶會話中使用蓖议,在當前會話結束時就會被除去。
??如果存儲過程的前面有兩個符號“##”讥蟆,那么把該存儲過程稱為全局臨時存儲過程勒虾,可以在所有用戶會話中使用,在使用該過程的最后一個會話結束時除去瘸彤。

(4)用戶定義的存儲過程
??用戶自定義的存儲過程由用戶創(chuàng)建的一組T-SQL語句集合組成修然,可以接收和返回用戶提供的參數,完成某些特定功能质况。
??存儲過程創(chuàng)建好且語法正確后愕宋,系統(tǒng)將存儲過程的名稱存儲在當前數據庫的系統(tǒng)表sysobject中;將存儲過程的文本存儲在當前數據庫的系統(tǒng)表syscomments中结榄。

創(chuàng)建存儲過程

存儲過程語法如下:

CREATE PROCEDURE|PROC [schema_name.] procedure_name
    -- Add the parameters for the stored procedure here
    [ { @parameter [ type_schema_name. ] data_type }  
        [ VARYING ] [ = default ] [ OUT | OUTPUT | [READONLY]  
    ] [ ,...n ]   
    [WITH <procedure_option> [ ,...n ]]
    [FOR REPLICATION]
AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] }

<procedure_option> ::=   
    [ ENCRYPTION ]  
    [ RECOMPILE ]  
    [ EXECUTE AS Clause ]  
  • schema_name:該過程所屬的架構的名稱中贝。如果在創(chuàng)建過程時未指定架構名稱,則自動分配正在創(chuàng)建過程的用戶的默認架構臼朗。
  • 可以通過使用一個#符號在procedure_name之前創(chuàng)建本地臨時過程(#procedure_name)或兩個#符號創(chuàng)建全局臨時過程(## procedure_name) 邻寿。局部臨時程序僅對創(chuàng)建了它的連接可見,并且在關閉該連接后將被刪除视哑。 全局臨時程序可用于所有連接绣否,并且在使用該過程的最后一個會話結束時將被刪除。
  • @parameter:指定過程中的參數挡毅,是局部的蒜撮,可以聲明一個或多個。
  • 如果指定了FOR REPLICATION跪呈,則無法聲明參數段磨。
  • parameter可以是輸入參數or輸出參數,若為輸入參數IN可以不寫庆械,系統(tǒng)默認薇溃;若為輸出參數則要加上OUTPUT。
  • 表值參數只能是 INPUT 參數缭乘,并且這些參數必須帶有 READONLY 關鍵字沐序。
  • 光標數據類型只能是輸出參數和必須附帶由 VARYING 關鍵字。
  • OUT | OUTPUT指示參數是輸出參數堕绩,使用 OUTPUT 參數將值返回給過程的調用方策幼。
  • [ =default ]:參數的默認值。 如果默認定義值奴紧,該函數可以執(zhí)行而無需指定該參數的值特姐。
  • WITH ENCRYPTION:SQL Server加密syscomments表中包含CREATE PROCEDURE語句文本的條目,即對用戶隱藏存儲過程的文本黍氮,不能從syscomments表中獲取該存儲過程的信息唐含。
  • WITH RECOMPILE:指示數據庫引擎不緩存該過程的計劃浅浮,該過程將在每次運行時重新編譯。如果指定了FOR REPLICATION捷枯,則不能使用此選項滚秩。
  • EXECUTE AS子句:指定在其中執(zhí)行過程的安全上下文。

關于參數

  • 存儲過程參數也可以帶有默認值淮捆,如:
create procedure pun_info @pubname varchar(20)='ALGOdata'
  • 存儲過程參數可以帶有通配符郁油,如:
create procedure pun_info 
   @name varchar(20)='D%'
as
  select name from authors where name like @name

關于輸出
①OUTPUT參數
??如果在過程定義中為參數指定 OUTPUT 關鍵字,則存儲過程在退出時可將該參數的當前值返回至調用程序攀痊。若要用變量保存參數值以便在調用程序中使用桐腌,則調用程序必須在執(zhí)行存儲過程時使用 OUTPUT 關鍵字。
??也可以在執(zhí)行過程時為 OUTPUT 參數指定輸入值苟径。 這將允許過程從調用程序接收值案站,使用該值更改或執(zhí)行操作,然后將新值返回給調用程序涩笤。
②使用返回代碼返回數據
??過程可以返回一個整數值(稱為“返回代碼”)嚼吞,以指示過程的執(zhí)行狀態(tài)。 使用 RETURN 語句指定過程的返回代碼蹬碧。 與 OUTPUT 參數一樣舱禽,執(zhí)行過程時必須將返回代碼保存到變量中,才能在調用程序中使用返回代碼值恩沽。
??RETURN是從查詢或過程中無條件退出誊稚,不執(zhí)行位于 RETURN 之后的語句。RETURN返回的不能是空值罗心,如果過程試圖返回空值里伯,將生成警告信息并返回 0 值。用輸出參數OUTPUT可以輸出任意類型的結果(不包括表類型)渤闷,而RETURN只能返回整型并且總能返回一個整型值疾瓮。一般的RETURN用來返回返回代碼(如0表示執(zhí)行成功,1表示未指定所需參數值)飒箭。
??RETURN和OUTPUT還可以出現在同一存儲過程中狼电,詳見示例(3)。

局限與限制

①在單個批處理中弦蹂,CREATE PROCEDURE 語句不能與其他 Transact-SQL 語句組合使用肩碟。
②以下語句不能用于存儲過程主體中的任何地方。



③過程可以引用尚不存在的表凸椿。 在創(chuàng)建時削祈,只進行語法檢查。 直到第一次執(zhí)行該過程時才對其進行編譯。 只有在編譯過程中才解析過程中引用的所有對象髓抑。 因此咙崎,如果語法正確的過程引用了不存在的表,則仍可以成功創(chuàng)建启昧;但如果被引用的表不存在叙凡,則過程將在執(zhí)行時將失敗。
④不能將某一函數名稱指定為參數默認值或者在執(zhí)行過程時傳遞給參數的值密末。 但是,您可以將函數作為變量傳遞跛璧,如以下示例中所示:

-- Passing the function value as a variable.  
DECLARE @CheckDate datetime = GETDATE();  
EXEC dbo.uspGetWhereUsedProductID 819, @CheckDate;   

⑤如果該過程對 SQL Server 的遠程實例進行更改严里,將無法回滾這些更改。 遠程過程不參與事務追城。

執(zhí)行存儲過程

調用存儲過程使用Execute|Exec關鍵字刹碾,不能省略。

Execute|Exec
{
  [@整形變量=]
  存儲過程名[,n]|@存儲過程變量名
  [[@過程參數=]參數值|@可變參數名 [OUTPUT]|[DEFAULT]]
  [,..,n]
  [WITH RECOMPILE]
}
  • @整形變量:可選座柱,代表存儲過程的返回狀態(tài)迷帜。
  • n:可選,用于對同名的過程分組色洞。
  • @過程參數:為存儲過程的參數賦值戏锹。

SQL Server提供了兩種傳遞參數的辦法:
(1)按位置傳遞參數,即傳遞的參數和定義時的參數順序一致火诸,如:
execute au_info 'Dull','Ann'
(2)通過參數名傳遞锦针,采用“參數=值”的形式,此時各個參數可以任意排序置蜀,如:
execute au_info @firstName='Dull',@lastName='Ann' 或
execute au_info @lastName='Ann',@firstName='Dull'

  • OUTPUT:指定該參數為輸出參數奈搜。
  • DEFAULT:指明該參數使用默認值。如果該參數定義時沒有指定默認值盯荤,則不能使用DEFAULT選項馋吗。
  • WITH RECOMPILE:強制在執(zhí)行存儲過程時重新對其進行編譯。

【示例】
(1)帶OUTPUT參數的存儲過程——最后的返回值存儲在調用程序聲明的OUTPUT變量中

create procedure Query_Relationer
   @QueryCID int,                   -- 輸入的形參
   @QueryRName varchar(20) OUTPUT   -- 輸出的形參
as
begin
  if exists(select rid from Customer where cid = @QueryCID)
    select @QueryRName = RName from Relationer
    where rid = (select rid from Customer where cid = @QueryCID and cStatus = 1)
  else
    set @QueryRName = '不存在'
end
go

調用過程如下:

declare @Relationer_name varchar(20),@Cust_ID int
execute Query_Relationer @Cust_ID=20103530,@Relationer_name OUTPUT
print '客戶ID為'+convert(char(8),@Cust_ID)+'的聯(lián)系人是:'+@Relationer_name

(2)帶Return參數的存儲過程

create proc up_user
as
delcare @age int
begin
  select @age=uage from user
  return @age
end

(3)同時帶Return和output參數的存儲過程

create proc up_user
@id int,
@name varchar(20) output
as
 declare @age int
 begin
  select @age=stuage,@name=stuname from stuinfo where uid=@id
  return @age
 end

調用過程如下:

declare @age int
declare @name varchar(20)
exec @age=up_user 2,@name output
-- 輸出age和name
select @age,@name

存儲過程傳遞集合參數以及返回秋秤、接收結果集

(1)傳遞集合參數

A宏粤、傳遞多個形參

B、使用表值參數
??使用表值參數類型將多個行插入表中航缀。 一下示例將創(chuàng)建參數類型商架,聲明表變量來引用它,填充參數列表芥玉,然后將值傳遞給存儲過程蛇摸。 存儲過程使用這些值將多個行插入表中。

/* Create a table type. */  
CREATE TYPE LocationTableType AS TABLE   
( LocationName VARCHAR(50)  
, CostRate INT );  
GO  
  
/* Create a procedure to receive data for the table-valued parameter. */  
CREATE PROCEDURE usp_InsertProductionLocation  
    @TVP LocationTableType READONLY  
    AS   
    SET NOCOUNT ON  
    INSERT INTO [AdventureWorks2012].[Production].[Location]  
           ([Name]  
           ,[CostRate]  
           ,[Availability]  
           ,[ModifiedDate])  
        SELECT *, 0, GETDATE()  
        FROM  @TVP;  
GO  
  
/* Declare a variable that references the type. */  
DECLARE @LocationTVP   
AS LocationTableType;  
  
/* Add data to the table variable. */  
INSERT INTO @LocationTVP (LocationName, CostRate)  
    SELECT [Name], 0.00  
    FROM   
    [AdventureWorks2012].[Person].[StateProvince];  
  
/* Pass the table variable data to a stored procedure. */  
EXEC usp_InsertProductionLocation @LocationTVP;  
GO  

(2)返回結果集

A灿巧、使用 OUTPUT 游標參數
??以下示例使用 OUTPUT 游標參數將過程的局部游標傳遞回執(zhí)行調用的批處理赶袄、過程或觸發(fā)器揽涮。
??首先,創(chuàng)建在 Currency表上聲明并打開一個游標的過程:

IF OBJECT_ID ( 'dbo.uspCurrencyCursor', 'P' ) IS NOT NULL  
    DROP PROCEDURE dbo.uspCurrencyCursor;  
GO  
CREATE PROCEDURE dbo.uspCurrencyCursor   
    @CurrencyCursor CURSOR VARYING OUTPUT  
AS  
    SET NOCOUNT ON;  
    SET @CurrencyCursor = CURSOR  
    FORWARD_ONLY STATIC FOR  
      SELECT CurrencyCode, Name  
      FROM Sales.Currency;  
    OPEN @CurrencyCursor;  
GO  

接下來饿肺,運行以下批處理:聲明一個局部游標變量蒋困,執(zhí)行上述過程以將游標賦值給局部變量,然后從該游標提取行敬辣。

DECLARE @MyCursor CURSOR;  
EXEC dbo.uspCurrencyCursor @CurrencyCursor = @MyCursor OUTPUT;  
WHILE (@@FETCH_STATUS = 0)  
BEGIN;  
     FETCH NEXT FROM @MyCursor;  
END;  
CLOSE @MyCursor;  
DEALLOCATE @MyCursor;  
GO  

B雪标、使用OUTPUT返回多個輸出參數
??這種方法缺點在于如果結果集中幾百個元素,那么在存儲過程就要聲明幾百個變量溉跃,十分麻煩村刨。

CREATE PROCEDURE Student.singS
      @id int,
      @name varchar(20) OUTPUT,
      @age int OUTPUT
AS
   select name,age from Student where id=@id
GO

調用段:

DECLARE @name varchar(20),@age int
EXECUTE Student.singS 28, @name OUTPUT,@age OUTPUT
print '學生的姓名為:'+@name+',年齡為:'+@age

C、SELECT返回結果集
??在存儲過程中寫一段返回一個結果集的SELECT語句撰茎,如果在調用段中僅僅EXEC procedure_name [parameter1...parametern]嵌牺,那么該SELECT語句的結果僅僅只會輸出到屏幕上,而不能用這個結果集做后續(xù)處理龄糊。如果要保存此結果集逆粹,只有一種方法,即通過使用 INSERT/EXEC 將其存儲到永久表炫惩、臨時表或表變量中僻弹,從而將結果流式處理到磁盤。

①把結果集存儲在臨時表
創(chuàng)建存儲過程:

CREATE PROCEDURE Proc1
 @a varchar(50)
AS
 SELECT id,name FROM Table1 WHERE name=@a

調用段:

-- 創(chuàng)建一個臨時表诡必,和存儲過程的結果集結構一致
CREATE TABLE #t1
(
  id int,
  name varchar(50)
)

-- 把結果集插入臨時表中
INSERT INTO #t1 EXEC Proc1 'Ada'
-- do something with results
--用完之后要把臨時表清空
DROP TABLE #t1

②把結果集存儲在表變量
??但這種方法在查詢的數據量較大的情況下比較影響性能奢方,查詢速度較慢,在數據量較小的情況下這種差異并不明顯爸舒。

create proc proc1 as
   select col1 from dbo.table1;

create proc proc2 as
   declare @t table(col1 int);
   insert @t (col1) exec proc1;
   -- do something with results

管理存儲過程

①查看存儲過程信息


②修改存儲過程

ALTER PROCEDURE|PROC [schema_name.] procedure_name
    -- Add the parameters for the stored procedure here
    [ { @parameter [ type_schema_name. ] data_type }  
        [ VARYING ] [ = default ] [ OUT | OUTPUT | [READONLY]  
    ] [ ,...n ]   
    [WITH <procedure_option> [ ,...n ]]
    [FOR REPLICATION]
AS { [ BEGIN ] sql_statement [;] [ ...n ] [ END ] }

<procedure_option> ::=   
    [ ENCRYPTION ]  
    [ RECOMPILE ]  
    [ EXECUTE AS Clause ]

③刪除存儲過程

DROP { PROC | PROCEDURE } [ IF EXISTS ] { [ schema_name. ] procedure } [ ,...n ]  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末蟋字,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子扭勉,更是在濱河造成了極大的恐慌鹊奖,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涂炎,死亡現場離奇詭異忠聚,居然都是意外死亡,警方通過查閱死者的電腦和手機唱捣,發(fā)現死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門两蟀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人震缭,你說我怎么就攤上這事赂毯。” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵党涕,是天一觀的道長烦感。 經常有香客問我,道長膛堤,這世上最難降的妖魔是什么手趣? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮肥荔,結果婚禮上绿渣,老公的妹妹穿的比我還像新娘。我一直安慰自己燕耿,他們只是感情好怯晕,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缸棵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谭期。 梳的紋絲不亂的頭發(fā)上堵第,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機與錄音隧出,去河邊找鬼踏志。 笑死,一個胖子當著我的面吹牛胀瞪,可吹牛的內容都是我干的针余。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼凄诞,長吁一口氣:“原來是場噩夢啊……” “哼圆雁!你這毒婦竟也來了?” 一聲冷哼從身側響起帆谍,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤伪朽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后汛蝙,有當地人在樹林里發(fā)現了一具尸體烈涮,經...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年窖剑,在試婚紗的時候發(fā)現自己被綠了坚洽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡西土,死狀恐怖讶舰,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤绘雁,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布橡疼,位于F島的核電站,受9級特大地震影響庐舟,放射性物質發(fā)生泄漏欣除。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一挪略、第九天 我趴在偏房一處隱蔽的房頂上張望历帚。 院中可真熱鬧,春花似錦杠娱、人聲如沸挽牢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽禽拔。三九已至,卻和暖如春室叉,著一層夾襖步出監(jiān)牢的瞬間睹栖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工茧痕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留野来,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓踪旷,卻偏偏與公主長得像曼氛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子令野,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內容

  • oracle存儲過程常用技巧 我們在進行pl/sql編程時打交道最多的就是存儲過程了舀患。存儲過程的結構是非常的簡單的...
    dertch閱讀 3,476評論 1 12
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現彩掐,斷路器构舟,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 當一個大型系統(tǒng)在建立時,會發(fā)現堵幽,很多的SQL操作是有重疊的狗超,個別計算是相同的,比如:業(yè)務系統(tǒng)中朴下,計算一張工單的計算...
    JackFrost_fuzhu閱讀 3,369評論 0 27
  • 任務需求:定時執(zhí)行的任務努咐,調用存儲過程,進行數據遷移殴胧。 存儲過程相關總結:(存儲過程的創(chuàng)建 不能伴隨有if exi...
    時待吾閱讀 3,060評論 0 4
  • 存儲過程是一組預先編輯好的SQL語句組成渗稍,編譯后存儲在數據庫中佩迟。 存儲過程可包含程序流、邏輯及對數據庫的查詢竿屹。它們...
    肉肉要次肉閱讀 4,396評論 0 1