天天看點

資料庫存儲過程

存儲過程(Procedure)可以說是一個記錄集吧,它是由一些T-SQL語句組成的代碼塊,這些T-SQL語句代碼像一個方法一樣實作一些功能(對單表或多表的增删改查),然後再給這個代碼塊取一個名字,在用到這個功能的時候調用他就行了。

存儲過程的好處:

1.由于資料庫執行動作時,是先編譯後執行的。然而存儲過程是一個編譯過的代碼塊,是以執行效率要比T-SQL語句高。

2.一個存儲過程在程式在網絡中互動時可以替代大堆的T-SQL語句,是以也能降低網絡的通信量,提高通信速率。

3.通過存儲過程能夠使沒有權限的使用者在控制之下間接地存取資料庫,進而確定資料的安全。

小結:總之存儲過程是好東西,在做項目時屬于必備利器,下面介紹存儲過程的基本文法。

一、存儲過程文法

--------------建立存儲過程-----------------

CREATE PROC [ EDURE ] procedure_name [ ; number ]
    [ { @parameter data_type }
        [ VARYING ] [ = default ] [ OUTPUT ]
    ] [ ,...n ]
[ WITH
    { RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]
[ FOR REPLICATION ]
AS sql_statement [ ...n ]

--------------調用存儲過程-----------------
EXECUTE Procedure_name '' --存儲過程如果有參數,後面加參數格式為:@參數名=value,也可直接為參數值value

--------------删除存儲過程-----------------
drop procedure procedure_name    --在存儲過程中能調用另外一個存儲過程,而不能删除另外一個存儲過程      

參數含義:

1.procedure_name :存儲過程的名稱,在前面加#為局部臨時存儲過程,加##為全局臨時存儲過程。

2.; number:是可選的整數,用來對同名的過程分組,以便用一條 DROP PROCEDURE 語句即可将同組的過程一起除去。例如,名為 orders 的應用程式使用的過程可以命名為

orderproc;1、orderproc;2 等。DROP PROCEDURE orderproc

語句将除去整個組。如果名稱中包含定界辨別符,則數字不應包含在辨別符中,隻應在 procedure_name 前後使用适當的定界符。

3.@parameter: 存儲過程的參數。可以有一個或多個。使用者必須在執行過程時提供每個所聲明參數的值(除非定義了該參數的預設值)。存儲過程最多可以有 2.100 個參數。

使用 @

符号作為第一個字元來指定參數名稱。參數名稱必須符合辨別符的規則。每個過程的參數僅用于該過程本身;相同的參數名稱可以用在其它過程中。預設情況下,參數隻能代替常量,而不能用于代替表名、列名或其它資料庫對象的名稱。有關更多資訊,請參見

EXECUTE。

4.data_type:參數的資料類型。所有資料類型(包括 text、ntext 和 image)均可以用作存儲過程的參數。不過,cursor 資料類型隻能用于 OUTPUT 參數。如果指定的資料類型為

cursor,也必須同時指定 VARYING 和 OUTPUT 關鍵字。有關 SQL Server

提供的資料類型及其文法的更多資訊,請參見資料類型。

說明 對于可以是 cursor 資料類型的輸出參數,沒有最大數目的限制。

5.VARYING: 指定作為輸出參數支援的結果集(由存儲過程動态構造,内容可以變化)。僅适用于遊标參數。 

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

7.OUTPUT :表明參數是傳回參數。該選項的值可以傳回給 EXEC[UTE]。使用 OUTPUT 參數可将資訊傳回給調用過程。Text、ntext 和 image 參數可用作 OUTPUT 參數。使用 OUTPUT 關鍵字的輸出參數可以是遊标占位符。 

8.RECOMPILE: 表明 SQL Server 不會緩存該過程的計劃,該過程将在運作時重新編譯。在使用非典型值或臨時值而不希望覆寫緩存在記憶體中的執行計劃時,請使用 RECOMPILE 選項。

9.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 語句。但有一些限制。

二、樣例

針對上面的表,我使用存儲過程對它做一些操作:

UserAccount
UserID UserName PassWord RegisterTime RegisterIP
12 6                    2012-12-31 6
18 5                    2013-01-01 5
19 1                    1
20 2                    2
21 3                    3
22 4                    4
23
25 7                    7
26 8                    8
NULL

針對上面的表,我使用存儲過程對它做一些操作(以SQL Server為基礎編寫樣例)。

2.1 隻傳回單一記錄集的存儲過程

-------------建立名為GetUserAccount的存儲過程----------------
create Procedure GetUserAccount
as
select * from UserAccount
go

-------------執行上面的存儲過程----------------
exec GetUserAccount      

結果:相當于運作 select * from UserAccount 這行代碼,結果為整個表的資料。

2.2 沒有輸入輸出的存儲過程

-------------建立名為GetUserAccount的存儲過程----------------

create Procedure inUserAccount
as
insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9)
go

-------------執行上面的存儲過程----------------

exec inUserAccount      

結果:相當于運作 insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(9,9,'2013-01-02',9) 這行代碼。

2.3 有傳回值的存儲過程

-------------建立名為GetUserAccount的存儲過程----------------

create Procedure inUserAccountRe
as
insert into UserAccount (UserName,[PassWord],RegisterTime,RegisterIP) values(10,10,'2013-01-02',10)
return @@rowcount
go

-------------執行上面的存儲過程----------------

exec inUserAccountRe      

解釋:這裡的@@rowcount為執行存儲過程影響的行數,執行的結果是不僅插入了一條資料,還傳回了一個值即 return value =1  ,這個可以在程式中擷取,稍後在c#調用存儲過程中會有說到。

2.4 有輸入參數和輸出參數的存儲過程

-------------建立名為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

-------------執行上面的存儲過程----------------

exec GetUserAccountRe '7',null      

解釋:@UserName為輸入參數,@UserID為輸出參數。 運作結果為@userID為COOUT(*)即 =1。

2.5 同時具有傳回值、輸入參數、輸出參數的存儲過程

-------------建立名為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

-------------執行上面的存儲過程----------------

exec GetUserAccountRe1 '7',null      

結果:@userID為COOUT(*)即 =1,Retun Value=1。

2.6 同時傳回參數和記錄集的存儲過程

-------------建立名為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

-------------執行上面的存儲過程----------------

exec GetUserAccountRe2 '7',null      

結果:傳回執行 select * from UserAccount 這句代碼的結果集,同時@userID為COOUT(*)即 =1,Retun Value=9。

2.7 傳回多個記錄集的存儲過程

------------建立名為GetUserAccount的存儲過程----------------

create Procedure GetUserAccountRe3
as
select * from UserAccount
select * from UserAccount where UserID>5
go

-------------執行上面的存儲過程----------------

exec GetUserAccountRe3      

結果:傳回兩個結果集,一個為 select * from UserAccount,另一個為 select * from UserAccount where UserID>5 。

附帶了一些SQL中的一些全局變量的查詢語句:

資料庫存儲過程
資料庫存儲過程
select APP_NAME ( ) as w --目前會話的應用程式

select @@IDENTITY   --傳回最後插入的辨別值 
select USER_NAME()    --傳回使用者資料庫使用者名

SELECT @@CONNECTIONS  --傳回自上次SQL啟動以來連接配接或試圖連接配接的次數。 
SELECT GETDATE() --目前時間 
SELECT @@CPU_BUSY/100  --傳回自上次啟動SQL 以來 CPU 的工作時間,機關為毫秒

USE tempdb SELECT @@DBTS  as w  --為目前資料庫傳回目前 timestamp 資料類型的值。這一 timestamp 值保證在資料庫中是唯一的。 
select @@IDENTITY as w --傳回最後插入的辨別值 
SELECT @@IDLE  as w  --傳回SQL自上次啟動後閑置的時間,機關為毫秒 
SELECT @@IO_BUSY AS w   --傳回SQL自上次啟動後用于執行輸入和輸出操作的時間,機關為毫秒 
SELECT @@LANGID AS w   --傳回目前所使用語言的本地語言辨別符(ID)。 
SELECT @@LANGUAGE AS w   --傳回目前使用的語言名 
SELECT @@LOCK_TIMEOUT as w  --目前會話的目前鎖逾時設定,機關為毫秒。 
SELECT @@MAX_CONNECTIONS  as w  --傳回SQL上允許的同時使用者連接配接的最大數。傳回的數不必為目前配置的數值 
EXEC sp_configure  --顯示目前伺服器的全局配置設定 
SELECT @@MAX_PRECISION as w --傳回 decimal 和 numeric 資料類型所用的精度級别,即該伺服器中目前設定的精度。預設最大精度38。 
select @@OPTIONS  as w  --傳回目前 SET 選項的資訊。 
SELECT @@PACK_RECEIVED as w  --傳回SQL自啟動後從網絡上讀取的輸入資料包數目。 
SELECT @@PACK_SENT as w  --傳回SQ自上次啟動後寫到網絡上的輸出資料包數目。 
SELECT @@PACKET_ERRORS as w  --傳回自SQL啟動後,在SQL連接配接上發生的網絡資料包錯誤數。 
SELECT @@SERVERNAME as w --傳回運作SQL伺服器名稱。 
SELECT @@SERVICENAME  as w --傳回SQL正在其下運作的系統資料庫鍵名 
SELECT @@TIMETICKS  as w --傳回SQL伺服器一刻度的微秒數 
SELECT @@TOTAL_ERRORS AS w  --傳回 SQL伺服器自啟動後,所遇到的磁盤讀/寫錯誤數。 
SELECT @@TOTAL_READ  as w  --傳回 SQL伺服器自啟動後讀取磁盤的次數。 
SELECT @@TOTAL_WRITE as w  --傳回SQL伺服器自啟動後寫入磁盤的次數。 
SELECT @@TRANCOUNT  as w  --傳回目前連接配接的活動事務數。 
SELECT @@VERSION as w  --傳回SQL伺服器安裝的日期、版本和處理器類型。      

SQLServer資料庫的一些全局變量

小結:上面我們建立了各式的存儲過程,下面看我們在c#中怎樣調用這些存儲過程。

三、c#調用存儲過程

調用以上寫的各種類型的存儲過程的C#代碼

資料庫存儲過程
資料庫存儲過程
public partial class ProcedureTest : System.Web.UI.Page
{
    public static  string conn = ConfigurationManager.ConnectionStrings["StuRelationDBConnectionString"].ConnectionString;
    public SqlConnection con = new SqlConnection(conn);
    protected void Page_Load(object sender, EventArgs e)
    {
        runGetUserAccountRe3();
    }

    //隻傳回單一記錄集的存儲過程GetUserAccount
    public void runGetUserAccount()
    {
        SqlDataAdapter dp = new SqlDataAdapter(common("GetUserAccount"));
        DataSet ds = new DataSet();
        // 填充dataset 
        dp.Fill(ds);
        rpt.DataSource = ds;
        rpt.DataBind();

    }

    //沒有輸入輸出的存儲過程inUserAccount
    public void runinUserAccount()
    {            
        con.Open();
        Label1.Text = common("inUserAccount").ExecuteNonQuery().ToString();
        con.Close();
    }

    //有傳回值的存儲過程inUserAccountRe
    public void runinUserAccountRe()
    {
        // 建立參數 
        SqlCommand cmd = common("inUserAccountRe");
        IDataParameter[] parameters = { 
             new SqlParameter("rval", SqlDbType.Int,4) 
         };
        // 将參數類型設定為 傳回值類型 
        parameters[0].Direction = ParameterDirection.ReturnValue;
        // 添加參數 
        cmd.Parameters.Add(parameters[0]);
        con.Open();
        // 執行存儲過程并傳回影響的行數 
        Label1.Text = cmd.ExecuteNonQuery().ToString();
        con.Close();
        // 顯示影響的行數和傳回值 
        Label1.Text += "-" + parameters[0].Value.ToString();
    }

    //有輸入參數和輸出參數的存儲過程
    public void runGetUserAccountRe()
    {
        SqlCommand cmd = common("GetUserAccountRe");
        // 建立參數 
        IDataParameter[] parameters = { 
             new SqlParameter("@UserName", SqlDbType.NChar,20) , 
             new SqlParameter("@UserID", SqlDbType.Int) ,
         };
        // 設定參數類型 
        parameters[0].Value = "7";  
        parameters[1].Direction = ParameterDirection.Output;  // 設定為輸出參數 
        // 添加參數 
        cmd.Parameters.Add(parameters[0]);
        cmd.Parameters.Add(parameters[1]);
        con.Open();
        // 執行存儲過程并傳回影響的行數 
        Label1.Text = cmd.ExecuteNonQuery().ToString();
        con.Close();           
        // 顯示影響的行數和輸出參數 
        Label1.Text += "-" + parameters[1].Value.ToString();
       
    }

    //同時具有傳回值、輸入參數、輸出參數的存儲過程GetUserAccountRe1
    public void runGetUserAccountRe1()
    {
        SqlCommand cmd = common("GetUserAccountRe1");
        // 建立參數 
        IDataParameter[] parameters = { 
             new SqlParameter("@UserName", SqlDbType.NChar,20) , 
             new SqlParameter("@UserID", SqlDbType.Int) ,
             new SqlParameter("rval", SqlDbType.Int,4) 
         };
        // 設定參數類型 
        parameters[0].Value = "7";
        parameters[1].Direction = ParameterDirection.Output;  // 設定為輸出參數 
        parameters[2].Direction = ParameterDirection.ReturnValue;  //設定為傳回值
        // 添加參數 
        cmd.Parameters.Add(parameters[0]);
        cmd.Parameters.Add(parameters[1]);
        cmd.Parameters.Add(parameters[2]);
        con.Open();
        // 執行存儲過程并傳回影響的行數 
        Label1.Text = cmd.ExecuteNonQuery().ToString();
        con.Close();
        // 顯示影響的行數和輸出參數 
        Label1.Text += "-輸出參數為:" + parameters[1].Value.ToString();
        Label1.Text += "-傳回值為:" + parameters[2].Value.ToString();

    }

    //同時傳回參數和記錄集的存儲過程GetUserAccountRe2
    public void runGetUserAccountRe2()
    {
        SqlCommand cmd = common("GetUserAccountRe2");
        // 建立參數 
        IDataParameter[] parameters = { 
             new SqlParameter("@UserName", SqlDbType.NChar,20) , 
             new SqlParameter("@UserID", SqlDbType.Int) ,
             new SqlParameter("rval", SqlDbType.Int,4) 
         };
        // 設定參數類型 
        parameters[0].Value = "7";
        parameters[1].Direction = ParameterDirection.Output;  // 設定為輸出參數 
        parameters[2].Direction = ParameterDirection.ReturnValue;  //設定為傳回值
        // 添加參數 
        cmd.Parameters.Add(parameters[0]);
        cmd.Parameters.Add(parameters[1]);
        cmd.Parameters.Add(parameters[2]);
        con.Open();
        // 執行存儲過程并傳回影響的行數 
        Label1.Text = cmd.ExecuteNonQuery().ToString();
        DataSet ds = new DataSet();
        SqlDataAdapter dt = new SqlDataAdapter(cmd);
        dt.Fill(ds);
        rpt.DataSource = ds;
        rpt.DataBind();
        con.Close();
        // 顯示影響的行數和輸出參數 
        Label1.Text += "-輸出參數為:" + parameters[1].Value.ToString();
        Label1.Text += "-傳回值為:" + parameters[2].Value.ToString();

    }

    //傳回多個記錄集的存儲過程
    public void runGetUserAccountRe3()
    {
        DataSet ds = new DataSet();
        SqlDataAdapter dt = new SqlDataAdapter(common("GetUserAccountRe3"));
        dt.Fill(ds);
        rpt1.DataSource = ds.Tables[0].DefaultView;
        rpt1.DataBind();
        rpt2.DataSource = ds.Tables[1].DefaultView;
        rpt2.DataBind();
    }
    
    public SqlCommand common(string proName)
    {
        
        SqlCommand cmd = new SqlCommand();
        // 設定sql連接配接 
        cmd.Connection = con;            
        // 如果執行語句 
        cmd.CommandText = proName;
        // 指定執行語句為存儲過程 
        cmd.CommandType = CommandType.StoredProcedure;
        return cmd;
    }
}      

Demos

你們的評論、回報,及對你們有所用,是我整理材料和博文寫作的最大的鼓勵和唯一動力。歡迎讨論和關注!

沒有整理與歸納的知識,一文不值!高度概括與梳理的知識,才是自己真正的知識與技能。

永遠不要讓自己的自由、好奇、充滿創造力的想法被現實的架構所束縛,讓創造力自由成長吧!

多花時間,關心他(她)人,正如别人所關心你的。理想的騰飛與實作,沒有别人的支援與幫助,是萬萬不能的。