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
調用: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
