存儲過程學習總結

 

SQLSERVER存儲過程使用說明書

 

引言

首先介紹一下什麼是存儲過程:存儲過程就是將常用的或很複雜的工作,預先用SQL語句寫好並用一個指定的名稱存儲起來,並且這樣的語句是放在數據庫中的,還可以根據條件執行不同SQL語句, 那麼以後要叫數據庫提供與已定義好的存儲過程的功能相同的服務時,只需調用execute,即可自動完成命令。
請大家先看一個小例子:

create proc query_book

as

select * from book

go

--調用存儲過程

exec query_book

請大家來了解一下存儲過程的語法。

Create PROC [ EDURE ] procedure_name [ ; number ]
    [ { @parameter data_type }
        [ VARYING ] [ = default ] [ OUTPUT ]
    ] [ ,...n ]

[ WITH
    { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]

[ FOR REPLICATION ]

AS sql_statement [ ...n ]

一、參數簡介

 1、 procedure_name

  新存儲過程的名稱。過程名必須符合標識符規則,且對於數據庫及其所有者必須唯一。

  要創建局部臨時過程,可以在 procedure_name 前面加一個編號符 (#procedure_name),要創建全局臨時過程,可以在 procedure_name 前面加兩個編號符 (##procedure_name)。完整的名稱(包括 #  ##)不能超過 128 個字符。指定過程所有者的名稱是可選的。

 2、;number

  是可選的整數,用來對同名的過程分組,以便用一條 Drop PROCEDURE 語句即可將同組的過程一起除去。例如,名爲 orders 的應用程序使用的過程可以命名爲 orderproc;1orderproc;2 等。Drop PROCEDURE orderproc 語句將除去整個組。如果名稱中包含定界標識符,則數字不應包含在標識符中,只應在 procedure_name 前後使用適當的定界符。

3、@parameter

  過程中的參數。在 Create PROCEDURE 語句中可以聲明一個或多個參數。用戶必須在執行過程時提供每個所聲明參數的值(除非定義了該參數的默認值)。存儲過程最多可以有 2100 個參數。

  使用@符號作爲第一個字符來指定參數名稱。參數名稱必須符合標識符的規則。每個過程的參數僅用於該過程本身;相同的參數名稱可以用在其它過程中。默認情況下,參數只能代替常量,而不能用於代替表名、列名或其它數據庫對象的名稱。

4、data_type

  參數的數據類型。所有數據類型(包括 textntext  image)均可以用作存儲過程的參數。不過,cursor 數據類型只能用於 OUTPUT 參數。如果指定的數據類型爲 cursor,也必須同時指定 VARYING  OUTPUT 關鍵字。

說明:對於可以是cursor 數據類型的輸出參數,沒有最大數目的限制。

5、VARYING

  指定作爲輸出參數支持的結果集(由存儲過程動態構造,內容可以變化)。僅適用於遊標參數。

6、default

  參數的默認值。如果定義了默認值,不必指定該參數的值即可執行過程。默認值必須是常量或 NULL。如果過程將對該參數使用 LIKE 關鍵字,那麼默認值中可以包含通配符(%_[]  [^])。

7、OUTPUT

  表明參數是返回參數。該選項的值可以返回給 EXEC[UTE]。使用 OUTPUT 參數可將信息返回給調用過程。Textntext  image 參數可用作 OUTPUT 參數。使用 OUTPUT 關鍵字的輸出參數可以是遊標佔位符。

8、n

  表示最多可以指定 2100 個參數的佔位符。

9、{RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION}

RECOMPILE 表明 SQL Server 不會緩存該過程的計劃,該過程將在運行時重新編譯。在使用非典型值或臨時值而不希望覆蓋緩存在內存中的執行計劃時,請使用 RECOMPILE 選項。

ENCRYPTION 表示 SQL Server 加密 syscomments 表中包含 Create PROCEDURE 語句文本的條目。使用 ENCRYPTION 可防止將過程作爲 SQL Server 複製的一部分發布。

  說明:在升級過程中,SQL Server 利用存儲在 syscomments 中的加密註釋來重新創建加密過程。

10、FOR REPLICATION

  指定不能在訂閱服務器上執行爲複製創建的存儲過程。.使用 FOR REPLICATION 選項創建的存儲過程可用作存儲過程篩選,且只能在複製過程中執行。本選項不能和 WITH RECOMPILE 選項一起使用。

11、AS

  指定過程要執行的操作。

12、sql_statement

  過程中要包含的任意數目和類型的 Transact-SQL 語句。但有一些限制。

13、 n

  是表示此過程可以包含多條 Transact-SQL 語句的佔位符。

14、註釋

/**/之間的爲註釋,可以包含一行和多行的說明文字。

15、 其他說明

  存儲過程的最大大小爲 128 MB

二、存儲過程的優點都有哪些呢?

1. 存儲過程只在創造時進行編譯即可,以後每次執行存儲過程都不需再重新編譯,而我們通常使用的SQL語句每執行一次就編譯一次,所以使用存儲過程可提高數據庫執行速度。

2. 經常會遇到複雜的業務邏輯和對數據庫的操作,這個時候就會用SP來封裝數據庫操作。當對數據庫進行復雜操作時(如對多個表進行Update,Insert,Query,Delete時),可將此複雜操作用存儲過程封裝起來與數據庫提供的事務處理結合一起使用。可以極大的提高數據庫的使用效率,減少程序的執行時間,這一點在較大數據量的數據庫的操作中是非常重要的。在代碼上看,SQL語句和程序代碼語句的分離,可以提高程序代碼的可讀性。

3. 存儲過程可以設置參數,可以根據傳入參數的不同重複使用同一個存儲過程,從而高效的提高代碼的優化率和可讀性。

4. 安全性高,可設定只有某此用戶才具有對指定存儲過程的使用權存儲過程的種類:

  (1)系統存儲過程:以sp_開頭,用來進行系統的各項設定.取得信息.相關管理工作, sp_help就是取得指定對象的相關信息。

  (2)擴展存儲過程 XP_開頭,用來調用操作系統提供的功能exec master..xp_cmdshell 'ping 10.8.16.1'

  (3)用戶自定義的存儲過程,這是我們所指的存儲過程常用格式  模版:Create procedure procedue_name [@parameter data_type][output][with]{recompile|encryption} as sql_statement

  解釋:output:表示此參數是可傳回的

with {recompile|encryption} recompile:表示每次執行此存儲過程時都重新編譯一次;encryption:所創建的存儲過程的內容會被加密。

三、實例講解

實例1:只返回單一記錄集的存儲過程。

  要求1:查詢表bankMoney的內容的存儲過程

create procedure sp_query_bankMoney
as
select * from bankMoney
go
exec sp_query_bankMoney

注*  在使用過程中只需要把中的SQL語句替換爲存儲過程名,就可以了很方便吧!

  實例2(向存儲過程中傳遞參數):

加入一筆記錄到表bankMoney,並查詢此表中userID= Zhangsan的所有存款的總金額。

Create proc insert_bank 

@param1 char(10),

@param2 varchar(20),

@param3 varchar(20),

@param4 int,

@param5  int output
  with encryption ---------加密
  as
  insert bankMoney (id,userID,sex,Money) Values(@param1,@param2,@param3, @param4)
select @param5=sum(Money) from bankMoney where userID='Zhangsan'
  go

  

在SQL Server查詢分析器中執行該存儲過程的方法是:

  declare @total_price int
  exec insert_bank '004','Zhangsan','男',100,@total_price output
  print '總餘額爲'+convert(varchar,@total_price)
  go

在這裏再囉嗦一下存儲過程的3種傳回值(方便正在看這個例子的朋友不用再去查看語法內容): 

  1.以Return傳回整數 
  2.以output格式傳回參數 
  3.Recordset

  傳回值的區別:   output和return都可在批次程式中用變量接收,而recordset則傳回到執行批次的客戶端中。

  實例3:使用帶有複雜 Select 語句的簡單過程

  下面的存儲過程從四個表的聯接中返回所有作者(提供了姓名)、出版的書籍以及出版社。該存儲過程不使用任何參數。

  USE pubs
  IF EXISTS (Select name FROM sysobjects
         Where name = 'au_info_all' AND type = 'P')
  Drop PROCEDURE au_info_all
  GO
  Create PROCEDURE au_info_all
  AS
  Select au_lname, au_fname, title, pub_name
  FROM authors a INNER JOIN titleauthor ta
      ON a.au_id = ta.au_id INNER JOIN titles t
      ON t.title_id = ta.title_id INNER JOIN publishers p
      ON t.pub_id = p.pub_id
  GO

  au_info_all 存儲過程可以通過以下方法執行:

  EXECUTE au_info_all
  -- or
  EXEC au_info_all

  如果該過程是批處理中的第一條語句,則可使用:

  au_info_all

  實例4:使用帶有參數的簡單過程

  Create PROCEDURE au_info
      @lastname varchar(40),
      @firstname varchar(20)
  AS
  Select au_lname, au_fname, title, pub_name
      FROM authors a INNER JOIN titleauthor ta
      ON a.au_id = ta.au_id INNER JOIN titles t
      ON t.title_id = ta.title_id INNER JOIN publishers p
      ON t.pub_id = p.pub_id
      Where  au_fname = @firstname
      AND au_lname = @lastname
  GO

  au_info 存儲過程可以通過以下方法執行:

  EXECUTE au_info 'Dull', 'Ann'
  -- or
  EXECUTE au_info @lastname = 'Dull', @firstname = 'Ann'
  -- or
  EXECUTE au_info @firstname = 'Ann', @lastname = 'Dull'
  -- or
  EXEC au_info 'Dull', 'Ann'
  -- or
  EXEC au_info @lastname = 'Dull', @firstname = 'Ann'
  -- or
  EXEC au_info @firstname = 'Ann', @lastname = 'Dull'

  如果該過程是批處理中的第一條語句,則可使用:

  au_info 'Dull', 'Ann'
  -- or
  au_info @lastname = 'Dull', @firstname = 'Ann'
  -- or
  au_info @firstname = 'Ann', @lastname = 'Dull'

  實例5:使用帶有通配符參數的簡單過程

  Create PROCEDURE au_info2
  @lastname varchar(30) = 'D%',
  @firstname varchar(18) = '%'
  AS
  Select au_lname, au_fname, title, pub_name
  FROM authors a INNER JOIN titleauthor ta
     ON a.au_id = ta.au_id INNER JOIN titles t
     ON t.title_id = ta.title_id INNER JOIN publishers p
     ON t.pub_id = p.pub_id
  Where au_fname LIKE @firstname
     AND au_lname LIKE @lastname
  GO

  au_info2 存儲過程可以用多種組合執行。下面只列出了部分組合:

  EXECUTE au_info2
  -- or
  EXECUTE au_info2 'Wh%'
  -- or
  EXECUTE au_info2 @firstname = 'A%'
  -- or
  EXECUTE au_info2 '[CK]ars[OE]n'
  -- or
  EXECUTE au_info2 'Hunter', 'Sheryl'
  -- or
  EXECUTE au_info2 'H%', 'S%'

 

 

四、系統存儲過程

用戶存儲過程: 用戶也可以編寫自己的存儲過程,並把它存放在數據庫中,供客戶端調用。

以上主要是用戶存儲過程,下面介紹一下系統存儲過程。

系統存儲過程: SQL Server本身提供了一些存儲過程,用於管理有關數據庫和用戶的信息。

 它的目的在於能夠方便地從系統表中查詢信息,或者完成與更新數據庫表相關的管理任務或其它的系統管理任務。

 系統存儲過程可以在任意一個數據庫中執行。創建並存放於系統數據庫master中,並且名稱以sp_或者xp_開頭。

 

    部分系統存儲過程:

     sp_addtype:用於定義一個用戶定義數據類型。

     sp_configure:用於管理服務器配置選項設置。

      xp_sendmail:用於發送電子郵件或尋呼信息。

     sp_stored_procedures:用於返回當前數據庫中的存儲過程的清單。

     sp_help:用於顯示參數清單和其數據類型。

     sp_helptext:用於顯示存儲過程的定義文本。

     sp_rename:用於修改當前數據庫中用戶對象的名稱。

     Sp_who:用於顯示使用數據庫的當前用戶

     sp_help:用於顯示參數清單和其數據類型。

     sp_depends:用於顯示存儲過程依據的對象或者依據存儲過程的對象

     sp_helptext:用於顯示存儲過程的定義文本。

一個調用系統存儲過程的例子:

exec sp_helptext query_book

 

 

 

五、注意事項:

存儲過程一般用來完成數據查詢和數據處理操作,所以在存儲過程中不可以使用創建數據庫對象的語句,

       即在存儲過程中一般不能含有以下語句:

      CREATE TABLE ; CREATE VIEW ; CREATE DEFAULT ;

       CREATE RULE ;CREATE TRIGGER ;CREATE PROCEDURE

六、返回值和狀態信息

無論什麼時候執行存儲過程,總要返回一個結果碼,用以指示存儲過程的執行狀態。

   如果存儲過程執行成功,返回的結果碼是0;如果存儲過程執行失敗,返回的結果碼一般是一個負數,它和失敗的類型有關。

    我們在創建存儲過程時,也可以定義自己的狀態碼和錯誤信息。

     執行存儲過程:

    例:執行帶參數的存儲過程,查詢大於歲的學生

      create proc show;3 ( @pno char(6) )

      as

      select * from person where Pno = @pno

      exec show;3 4

    例: CREATE Procedure sp_getstu;1

      AS

      SELECT * FROM 學生

    例:帶參數的存儲過程,查詢大於指定年齡的學生

      CREATE proc sp_getstu;2 (@sage int)

      AS

      SELECT * FROM 學生WHERE 年齡> @sage

     例: 帶輸出參數的存儲過程,查詢指定學生的年齡

CREATE proc sp_getstu;3 ( @name char(10) , @age int output )

      AS

      SELECT @age=年齡 FROM 學生WHERE 姓名= @name

      Declare @sage int

      Exec sp_getstu;3 '張三',@sage

      Print @sage

 

     例:帶參數和返回狀態值的存儲過程。

      CREATE PROCedure sp_getstu;3 (@sage int =NULL )

      AS

      IF @sage IS NULL

          BEGIN

              PRINT '必須提供一個數值作參數!'

              RETURN 13

          END

      IF NOT EXISTS (SELECT * FROM student WHERE sage > @sage)

          BEGIN

              PRINT '沒有滿足條件的記錄!'

             RETURN -103

          END

          SELECT * FROM student WHERE sage > @sage

          RETURN 0

      DECLARE @status int

      EXECUTE @status=sp_getstu;3 22

      print @status

 

七、存儲過程中游標的使用

 

1、需要遊標的數據操作

    當select語句的結果中包含多個元組時,使用遊標可以逐個存取這些元組

    活動集:select語句返回的元組的集合

    當前行:活動集中當前處理的那一行。遊標即是指向當前行的指針。

2、遊標分類

    滾動遊標:遊標的位置可以來回移動,可在活動集中取任意元組。

    非滾動遊標:只能在活動集中順序地取下一個元組。

    更新遊標:數據庫對遊標指向的當前行加鎖,當程序讀下一行數據時,本行數據解鎖,下一行數據加鎖。

 

3、定義與使用遊標的語句

   declare : declare  遊標名[scroll]  cursor  for select語句[for update [of列表名]]

定義一個遊標,使之對應一個select語句

    forupdate任選項,表示該遊標可用於對當前行的修改與刪除

   open打開一個遊標,執行遊標對應的查詢,結果集合爲該遊標的活動集

    open  遊標名

   fetch在活動集中將遊標移到特定的行,並取出該行數據放到相應的變量中

fetch [next | prior | first | last| current | relative n | absolute m] 遊標名into  [變量表]

close關閉遊標,釋放活動集及其所佔資源。需要再使用該遊標時,執行open語句

    close  遊標名

   deallocate 刪除遊標,以後不能再對該遊標執行open語句

    deallocate遊標名

   @@FETCH_STATUS返回被FETCH 語句執行的最後遊標的狀態.

     0 fetch語句成功  -1 fetch語句失敗-2 被提取的行不存在

4、遊標實例

     例:查詢電子商務系學生信息,性別爲女輸出爲female,否則輸出爲male?

      declare c1 cursor for select sno,sname,ssex from studentwhere sdept='ec'

      declare @sno char(10),@sname char(10),@ssex char(2)

      Open c1

      Fetch c1 into @sno,@sname,@ssex

      While @@fetch_status==0

      Begin

      if @ssex='女'

           begin set @ssex='female' end

      else

          begin set @ssex='male' end

      Select @sno,@sname ,@ssex

          Fetch c1 into @sno,@sname,@ssex

      end

例:
    ALTER PROC [dbo].[dnt_UserRecoveryByUserName]
    @username    NVARCHAR(50)
AS

BEGIN

    DECLARE    @uid INT;
    DECLARE    @tid INT;
    DECLARE    @replies INT;
    DECLARE    @temp varchar(50);

    SET @uid        = (SELECTTOP(1) uid FROM dnt_users WHERE username = '@username');
    SET @tid        = 0;
    SET @replies    = 0;

    UPDATE dnt_users SET accessmasks = 0 WHERE uid = @uid;
    UPDATE dnt_userforum SET groupid = 5 WHERE groupid = 4 ANDuid = @uid;
    UPDATE dnt_posts SET invisible = 0 WHERE invisible = -1 ANDposterid = @uid;

    -- 定義一遊標
    DECLARE Ctemp CURSOR FOR SELECT tid FROM dnt_topics WHEREposterid = @uid FOR READ only -- FOR UPDATE

    OPEN Ctemp  
        FETCH next FROM Ctemp INTO @tid;
        WHILE (@@fetch_status = 0)
        BEGIN
            SET @replies = (SELECTCOUNT(1) FROM dnt_posts WHERE tid = @tid AND layer > 0);
            UPDATE dnt_topics SETreplies = @replies WHERE posterid = @uid AND tid = @tid;
            FETCH next FROM CtempINTO @tid;
        END
    CLOSE Ctemp;
    DEALLOCATE Ctemp;

END

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章