數據庫之創建存儲過程


sql 版本

 

 

 

 

sql servre 幫助文檔中對存儲過程的解釋

  創建存儲過程。存儲過程是已保存的 Transact-SQL 語句集合,或對 Microsoft .NET Framework 公共語言運行時 (CLR) 方法的引用,

  可接收並返回用戶提供的參數。可以創建過程供永久使用,或在一個會話(局部臨時過程)中臨時使用,或在所有會話(全局臨時過程)中臨時使用

創建存儲過程可以用 proc或者procedure關鍵字 proc是簡寫

 

 

目前有個簡單的庫(TestInfo),庫里面有個簡單的表(Show) 表里面有些簡單的數據

 

編寫個簡單的存儲過程,沒有任何參數和返回值的存儲過程

USE TestInfo
GO
IF OBJECT_ID('proc_show01','P') IS NOT NULL --存儲過程是否存在 
DROP PROCEDURE proc_show01 --刪除存儲過程
GO
CREATE PROC proc_show01
AS
SELECT * FROM Show

執行sql語句成功后,在sql中可以看到存儲過程已經創建

 

 

OBJECT_ID(object_name,'object_type);函數用於判斷對象是否存在
object_type對應的類型如下
  AF = Aggregate function (CLR)
  C = CHECK constraint --檢查約束
  D = DEFAULT (constraint or stand-alone)
  F = FOREIGN KEY constraint --外鍵約束
  FN = SQL scalar function --函數
  FS = Assembly (CLR) scalar-function
  FT = Assembly (CLR) table-valued function
  IF = SQL inline table-valued function
  IT = Internal table
  P = SQL Stored Procedure --存儲過程
  PC = Assembly (CLR) stored-procedure --CLR存儲過程
  PG = Plan guide
  PK = PRIMARY KEY constraint --主鍵約束
  R = Rule (old-style, stand-alone) --規則
  RF = Replication-filter-procedure
  S = System base table --數據庫
  SN = Synonym
  SQ = Service queue
  TA = Assembly (CLR) DML trigger --CLR觸發器
  TF = SQL table-valued-function
  TR = SQL DML trigger --DML觸發器
  U = Table (user-defined) --數據表
  UQ = UNIQUE constraint --唯一約束
  V = View --視圖
  X = Extended stored procedure

比如上面的判斷存儲過程是否存在 OBJECT_ID('proc_show01','P') 獲取存儲過程名為:proc_show01
判斷表是否存在 OBJECT_ID('info','U') 獲取表名為:info
或者:
select * from sysobjects where name='info' and type='u'

 SQL Server支持五種類型的完整性約束
  NOT NULL (非空)--防止NULL值進入指定的列,在單列基礎上定義,默認情況下,ORACLE允許在任何列中有NULL值.
  CHECK (檢查)--檢查在約束中指定的條件是否得到了滿足.
  UNIQUE (唯一)--保證在指定的列中沒有重復值.在該表中每一個值或者每一組值都將是唯一的.
  PRIMARY KEY (主鍵)--用來唯一的標識出表的每一行,並且防止出現NULL值,一個表只能有一個主鍵約束.
  POREIGN KEY (外部鍵)--通過使用公共列在表之間建立一種父子(parent-child)關系,在表上定義的外部鍵可以指向主鍵或者其他表的唯一鍵.

 

在.Net轉編寫測試代碼。調用剛創建的存儲過程

 /// 執行存儲過程
        /// </summary>
        /// <param name="cmdText">存儲過程的名稱</param>
        /// <param name="param">存儲過程參數</param>
        /// <returns></returns>

        public static DataTable GetPro2(string cmdText, params SqlParameter[] param)
        {
            DataTable dt = new DataTable();
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                SqlCommand cmd = new SqlCommand(cmdText, conn);
                // 指定執行語句為存儲過程
                cmd.CommandType = CommandType.StoredProcedure;
                if (param != null && param.Length != 0)
                {
                    cmd.Parameters.AddRange(param);
                }
                SqlDataAdapter dp = new SqlDataAdapter(cmd);
                dp.Fill(dt);
            }
            return dt;
        }

 

  成功后的界面
 

 

 

編寫一個有輸入參數的存儲過程

USE TestInfo
GO
IF OBJECT_ID('proc_show01','P') IS NOT NULL--存儲過程是否存在 
DROP PROCEDURE proc_show01 --刪除存儲過程
GO
CREATE PROC proc_show01
(
    @name nvarchar(20)
)
AS
SELECT * FROM Show where @name=Name

 

測試看結果,傳入 name="張三"

 

 

編寫存儲過程的可空參數,當存儲過程參數有默認值的時候,

那么.net在調用存儲過程的時候。可以不用傳參數。否則如果不傳這會報錯

所以:

除非定義了參數的默認值或者將參數設置為等於另一個參數,否則用戶必須在調用過程時為每個聲明的參數提供值

USE TestInfo
GO
IF OBJECT_ID('proc_show01','P') IS NOT NULL --存儲過程是否存在 
DROP PROCEDURE proc_show01 --刪除存儲過程
GO
CREATE PROC proc_show01
(
    @name nvarchar(20) = null --默認值為空
)
AS
IF @name is null
begin
    set @name='劉德華' --當沒有傳值的時候。設置默認值
end
select * from Show where @name = name

 

測試。當不傳值的時候,默認查詢的是 “劉德華”

 

 

 

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

USE TestInfo
GO
IF OBJECT_ID('proc_show01','P') IS NOT NULL--存儲過程是否存在 
DROP PROCEDURE proc_show01 --刪除存儲過程
GO
CREATE PROC proc_show01
(
    @id int output, --輸出參數,輸出id
    @name nvarchar(20) = null --默認值為空
)
AS
IF @name is null
begin
    set @name='劉德華' --當沒有傳值的時候。設置默認值
    set @id=0
    select * from Show where name = @name
    --return
end
else
    begin
        set @id=(select ID from Show where name = @name)
        select * from Show where name = @name
    end

 

既然有輸出參數。那么得修改上面的.Net代碼。如下

/// <summary>
        /// 調用存儲過程
        /// </summary>
        /// <param name="cmdText">存儲過程名稱</param>
        /// <param name="v1">輸出參數(這里是ID)</param>
        /// <param name="param">參數</param>
        /// <returns></returns>
        public static DataTable GetPro1(string cmdText, out int v1, params SqlParameter[] param)
        {
            DataTable dt = new DataTable();
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                SqlCommand cmd = new SqlCommand(cmdText, conn);
                // 指定執行語句為存儲過程
                cmd.CommandType = CommandType.StoredProcedure;
                if (param != null && param.Length != 0)
                {
                    cmd.Parameters.AddRange(param);
                }
                SqlDataAdapter dp = new SqlDataAdapter(cmd);
                //dp.SelectCommand.Parameters.AddRange(param);
                dp.Fill(dt);

                /*
                  獲取輸出參數。
                 * 這里在組裝參數的時候。指定了數組的第一個數是輸出參數
                 */
                v1 = Convert.ToInt32(param[0].Value); 
          //也可以通過SqlCommand根據參數名稱獲取存儲過程的返回值,跟param[0].Value是同樣的效果
                object id = cmd.Parameters["@id"].Value; }
return dt; }

 

在組裝參數的時候。要指定哪些參數是輸入參數。哪些是輸出參數,默認是輸入參數(Input)。

如果是輸入(或者輸入輸出)參數。則必須要賦值。在存儲過程中沒有給默認值的情況下

在下圖可以看出。有輸入參數有兩個 Input 和 InputOutput

.Net 有個ParameterDirection 枚舉類

 

sql 中有out 輸出參數,output 輸入輸出參數

CREATE PROC proc_show01
(
    @id int output, --輸入輸出參數,輸出id
    @ck int out,
    @name nvarchar(20) = null --默認值為空 ,默認是輸入參數
)

但在.Net都是output。因為output就是輸入輸入參數的總稱

 param[3].Direction = ParameterDirection.Output

 

測試代碼

 static void Main(string[] args)
        {
            //SqlParameter p = new SqlParameter("@name", "張三");

            //拼裝參數
            SqlParameter[] param = { 
                                        new SqlParameter("@id",SqlDbType.Int),
                                        new SqlParameter("@name",SqlDbType.NVarChar)
                                   };

            //設置參數是輸出參數
            param[0].Direction = ParameterDirection.Output;
            param[1].Value = "王五";
            int id;
            DataTable dt = SQLHelper.GetPro1("proc_show01", out id, param); //沒有參數
        }

運行看結果

 

 

 

上面用 param[0].Direction = ParameterDirection.Output; 指定第一個參數是輸出參數

然后通過 v1 = Convert.ToInt32(param[0].Value); 獲取存儲過程返回的值

 

從ParameterDirection枚舉可以看出輸入輸出參數都測試過了。還有一個操作的返回值沒有測試

 

那么來編寫一個有操作類返回值的存儲過程

USE TestInfo
GO
IF OBJECT_ID('proc_show01','P') IS NOT NULL--存儲過程是否存在 
DROP PROCEDURE proc_show01 --刪除存儲過程
GO
CREATE PROC proc_show01
(
    @id int output, --輸出參數,輸出id
    @name nvarchar(20) = null --默認值為空
)
AS
/*
定義一個變量,返回一個值 
也可以不定義變量,直接用return 返回
*/
declare @returnValue int 
IF @name is null
begin
    set @name='劉德華' --當沒有傳值的時候。設置默認值
    set @id=0
    select * from Show where name = @name
    set @returnValue=10
    --return 0 --這里同樣可以
end
else
    begin
        set @id=(select ID from Show where name = @name)
        select * from Show where name = @name
        set @returnValue=11
    end
return @returnValue --返回值

 

用 ParameterDirection.ReturnValue 指定是返回值

 

GetPro1則要加一個out 參數

 public static DataTable GetPro1(string cmdText, out int v1,out int v2, params SqlParameter[] param)

則: v2 = Convert.ToInt32(param[1].Value);

 

測試看效果

 

存儲過程里面也可以執行一個新增操作。然后返回剛新增的ID,比如:

begin
    set @name='劉德華' --當沒有傳值的時候。設置默認值
    --set @id=0
    select * from Show where name = @name
    set @returnValue=10
    --return 0 --這里同樣可以
    insert Show(Name,Remark)VALUES('新增','地球');
    set @id = @@IDENTITY --返回新增的ID
end

 

上面都是通過.net代碼訪問存儲過程,那么通過Transact-SQL語句怎么執行呢?

Transact-SQL 語句用exec(簡寫)關鍵字 ,全稱是execute關鍵字

因為存儲過程的參數順序是

 

所以可以這樣直接傳參數,但順序必須根據存儲過程定義參數順序一樣

 

 

 

上面只是獲取結果集。那么怎獲取輸出參數(outPut)和返回值呢(ReturnValue)

因為返回值是方法的返回值。所以可以變量名=存儲過程名稱 是不是跟.Net中很相似?

declare @m int --定義變量接收值
declare @result int 
exec @result=[proc_show01] @name='趙六',@id=@m output --一定要注名是output
select @m as '輸出參數',@result as '返回值'

 

執行結果

 

其實就是參數名= 值 @name='趙六',@id=@m  的方式。因為

一旦使用了 '@name = value' 形式之后,所有后續的參數就必須以 '@name = value' 的形式傳遞。

 

用這種方式。順序可以不用跟存儲過程中定義參數的順序相同

 

如果不用@name = value'的方式同樣可以,

但這樣直接傳參數,但順序必須根據存儲過程定義參數順序一樣,返回值放在最前面

 

DECLARE @name varchar
--set @name='張三'
DECLARE @id int
DECLARE @result int
EXEC @result = proc_show01 @id output,'張三' --這里傳參數的順序一定要對應
--EXEC @result = proc_show01 @id output,@name 
select @id as '輸出參數',@result as '返回值'

 

 

結果一樣,其實不一樣。因為傳的參數不一樣,哈哈哈

 

 

 

存儲過程與SQL語句對比 (知識來源於網絡)

優勢:

1、提高性能
  SQL語句在創建過程時進行分析和編譯。 存儲過程是預編譯的,在首次運行一個存儲過程時,查詢優化器對其進行分析、

  優化,並給出最終被存在系統表中的存儲計划,這樣,在執行過程時便可節省此開銷。


2、降低網絡開銷
  存儲過程調用時只需用提供存儲過程名和必要的參數信息,從而可降低網絡的流量。


3、便於進行代碼移植
  數據庫專業人員可以隨時對存儲過程進行修改,但對應用程序源代碼卻毫無影響,從而極大的提高了程序的可移植性。


4、更強的安全性
  1)系統管理員可以對執行的某一個存儲過程進行權限限制,避免非授權用戶對數據的訪問
  2)在通過網絡調用過程時,只有對執行過程的調用是可見的。 因此,惡意用戶無法看到表和數據庫對象名稱、嵌入自己的 Transact-SQL 語句或搜索關鍵數據。
  3)使用過程參數有助於避免 SQL 注入攻擊。 因為參數輸入被視作文字值而非可執行代碼,所以,攻擊者將命令插入過程內的 Transact-SQL 語句並損害安全性將更為困難。
  4)可以對過程進行加密,這有助於對源代碼進行模糊處理。 

 

劣勢:

1、存儲過程需要專門的數據庫開發人員進行維護,但實際情況是,往往由程序開發員人員兼職

2、設計邏輯變更,修改存儲過程沒有SQL靈活

為什么在實際應用中,存儲過程用到相對較少呢?

在通常的項目研發中,用存儲過程卻相對較少,這是為什么呢?
分析原因如下:
  1)沒有特定的數據庫開發人員,普通程序員兼職進行數據庫操作
  2)程序員往往只需操作程序,即可完成數據訪問,無需再在數據庫上進行開發
  3)項目需求變動比較頻繁,修改SQL語句比較方便,特別是涉及邏輯變更 

存儲過程與SQL語句如何抉擇?

基於實際應用的經驗,給予如下建議:

  1、在一些高效率或者規范性要求比較高的項目,建議采用存儲過程
  2、對於一般項目建議采用參數化命令方式,是存儲過程與SQL語句一種折中的方式
  3、對於一些算法要求比較高,涉及多條數據邏輯,建議采用存儲過程

 

 

//新增字段前判斷字段是否存在
 
IF  NOT  EXISTS ( select  name  from  syscolumns  where  id=object_id(N 'tb' AND  NAME = 'name' )
  BEGIN
  ALTER  TABLE  tb
  ADD name  VARCHAR (100)  NULL
  END
GO

--新增字段 ALTER TABLE dbo.info ADD test bit NULL --添加描述 EXECUTE sp_addextendedproperty N'MS_Description', '這里是描述', N'user', N'dbo', N'table', N'info', N'column', N'test' --更新說明 EXEC sp_updateextendedproperty 'MS_Description','字段1','user',dbo,'table','info','column',test --刪除屬性 EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table','info','column',test


1、添加字段

alter table 表名 add 字段名 type not null default 0

2、修改字段名

alter table 表名 rename column A to B

3、修改字段類型

alter table 表名 modify column UnitPrice decimal(18, 4) not null 

4、修改字段默認值

alter table 表名 drop constraint 約束名字   ------說明:刪除表的字段的原有約束

alter table 表名 add constraint 約束名字 DEFAULT 默認值 for 字段名稱 -------說明:添加一個表的字段的約束並指定默認值

5、刪除字段

alter table 表名 drop column 字段名;

 

收集網絡刪的一個查詢表的信息

 1 SET QUOTED_IDENTIFIER ON
 2 GO
 3 
 4 
 5 CREATE PROCEDURE [dbo].[sp_SelectTable]
 6     @tableName nvarchar(500)
 7 AS
 8 BEGIN
 9     SET NOCOUNT ON;
10         SELECT 
11         表名       = case when a.colorder=1 then d.name else '' end,
12         表說明     = case when a.colorder=1 then isnull(f.value,'') else '' end,
13         字段序號   = a.colorder,
14         字段名     = a.name,
15         標識       = case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then ''else '' end,
16         主鍵       = case when exists(SELECT 1 FROM sysobjects where xtype='PK' and parent_obj=a.id and name in (
17                          SELECT name FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid))) then '' else '' end,
18         類型       = b.name,
19         占用字節數 = a.length,
20         長度       = COLUMNPROPERTY(a.id,a.name,'PRECISION'),
21         小數位數   = isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0),
22         允許空     = case when a.isnullable=1 then ''else '' end,
23         默認值     = isnull(e.text,''),
24         字段說明   = isnull(g.[value],'')
25     FROM 
26         syscolumns a
27     left join 
28         systypes b 
29     on 
30         a.xusertype=b.xusertype
31     inner join 
32         sysobjects d 
33     on 
34         a.id=d.id  and d.xtype='U' and  d.name<>'dtproperties'
35     left join 
36         syscomments e 
37     on 
38         a.cdefault=e.id
39     left join 
40     sys.extended_properties   g 
41     on 
42         a.id=G.major_id and a.colid=g.minor_id  
43     left join
44     sys.extended_properties f
45     on 
46         d.id=f.major_id and f.minor_id=0
47     where 
48         d.name in(@tableName)    --如果只查詢指定表,加上此where條件,tablename是要查詢的表名;去除where條件查詢所有的表信息
49     order by 
50         a.id,a.colorder
51 END
52 GO
View Code

調用:exec sp_SelectTable @tableName='表名'

 

 源碼

參考資料

   http://www.cnblogs.com/cwyblog/archive/2013/04/21/3034281.html

   http://www.cnblogs.com/yank/p/4235609.html

 http://www.cnblogs.com/SkySoot/archive/2012/02/10/2345185.html

http://www.cnblogs.com/sosoft/p/3535696.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM