SQL Server 中 EXEC 與 SP_EXECUTESQL 的區別
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
MSSQL為我們提供了兩種動態執行SQL語句的命令,分別是 EXEC 和 SP_EXECUTESQL ,我們先來看一下兩種方式的用法。 先建立一個表,并添加一些數據來進行演示: ? CREATE TABLE t_student( Id INT NOT NULL, Name NVARCHAR (10) NULL, Age TINYINT NULL, School NVARCHAR(20) NULL, Class NVARCHAR(10) NULL, Score FLOAT NULL, CONSTRAINT [PK_Student_Id] PRIMARY KEY CLUSTERED(Id) ) GO INSERT INTO t_student VALUES(1,'張小紅',8,'育才小學','一班',92) INSERT INTO t_student VALUES(2,'王麗麗',8,'育才小學','一班',90) INSERT INTO t_student VALUES(3,'張燕',7,'云華小學','二班',86) INSERT INTO t_student VALUES(4,'劉華',6,'云華小學','二班',85) 一、EXEC EXEC命令可以執行一個存儲過程也可以執行一個動態SQL語句。先來看看怎么執行存儲過程: 新建一個存儲過程 SP_GetStudent ,返回 成績大于90 分的學生: CREATE PROCEDURE [dbo].[Sp_GetStudent] @Score FLOAT, @Nums INT OUTPUT AS BEGIN SET NOCOUNT ON; SELECT * FROM t_student WHERE Score >=@Score SELECT @Nums=COUNT(1) FROM t_student WHERE Score >=@Score IF(@Nums>0) RETURN 1 ELSE RETURN 0 END GO 該存儲過程涉及了 查詢操作、返回值和輸出參數,我們來看用EXEC 命令如何調用: DECLARE @return_value int, @OutNums int EXEC @return_value = [dbo].[Sp_GetStudent] @Score = 90, @Nums = @OutNums OUTPUT SELECT @OutNums as N'大于90分的人數' SELECT '返回值' = @return_value GO 執行結果: 我們發現EXEC 執行存儲過程和我們平時程序執行一個方法是幾乎一樣的,返回值參數 直接就可以等于存儲過程的執行后的返回值,輸出參數 在后面需要增加 OUTPUT 關鍵字。 執行存儲過程不是重點,重點是執行動態sql語句,同樣看一下例子: DECLARE @TableName NVARCHAR(50),@Sql NVARCHAR(MAX),@Score INT; SET @TableName = 't_Student'; SET @Score = 90; SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +'WHERE Score >= '+CAST(@Score AS NVARCHAR(10)) EXEC (@sql); 執行結果: 注意:在執行拼接SQL 語句的時候,的EXEC括號中只允許包含一個字符串變量,但是可以串聯多個變量,如果我們直接執行這個SQL語句: --這是錯誤的調用 EXEC ('SELECT * FROM '+QUOTENAME(@TableName) +'WHERE Score >= '+CAST(@Score AS NVARCHAR(10))); 執行就會提示錯誤。但是這樣就沒有問題: DECLARE @TableName NVARCHAR(50),@Sql NVARCHAR(MAX),@Score INT DECLARE @Sql2 NVARCHAR(MAX) SET @TableName = 't_Student'; SET @Score = 90; SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) SET @Sql2=' WHERE Score >= '+CAST(@Score AS NVARCHAR(10)) EXEC (@sql+@sql2) EXEC 執行拼接sql語句的時候不支持 嵌入式參數,如下: DECLARE @OUT_Nums INT,@IN_Score INT,@Sql NVARCHAR(MAX) SET @IN_Score = 90 SET @sql = 'SELECT @Nums=COUNT(1) FROM t_student WHERE Score >= @Score' EXEC (@sql)
通過上面的代碼發現,EXEC 執行拼接的SQL語句的時候,不支持內嵌參數,包括輸入參數和輸出參數。有的時候我們想把得到的count(*)傳出來,用EXEC是不好辦到的。接下來,再來看看SP_EXECUTESQL的使用: 二、SP_EXECUTESQL: SP_EXECUTESQL 是在 SQL 2005中引入的新的系統存儲過程,也是用來處理動態SQL 語句的。它比EXEC 更加靈活,首先也執行一下第一次的拼接SQL語句: DECLARE @TableName NVARCHAR(50),@Sql NVARCHAR(MAX),@Score INT; SET @TableName = 't_Student'; SET @Score = 90; SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +'WHERE Score >= '+CAST(@Score AS NVARCHAR(10)) EXEC SP_EXECUTESQL @sql --注意這里沒有了() 執行結果: SP_EXECUTESQL 支持內嵌參數: 先來看一下SP_EXECUTESQL的語法: sp_executesql [ @stmt = ] stmt [ {, [@params=] N'@parameter_name data_type [ OUT | OUTPUT ][,...n]' } {, [ @param1 = ] 'value1' [ ,...n ] } ] 參數字符串中定義的第一個參數的值。該值可以是 Unicode 常量,也可以是 Unicode 變量。必須為 stmt 中包含的每個參數提供參數值。如果 stmt 中的 Transact-SQL 語句或批處理沒有參數,則不需要這些值。
[ OUT | OUTPUT ] 指示參數是輸出參數。除非是公共語言運行 (CLR) 過程,否則 text、ntext 和 image 參數均可用作 OUTPUT 參數。使用 OUTPUT 關鍵字的輸出參數可以為游標占位符,CLR 過程除外。
n 附加參數值的占位符。這些值只能為常量或變量,不能是很復雜的表達式(例如函數)或使用運算符生成的表達式。 0(成功)或非零(失敗)
結果集:從生成 SQL 字符串的所有 SQL 語句返回結果集
看不懂沒有關系,通過例子就會非常明白的,依舊還執行上面的 SQL 語句: DECLARE @OUT_Nums INT,@IN_Score INT,@Sql NVARCHAR(MAX) SET @IN_Score = 90 SET @sql = 'SELECT @Nums=COUNT(1) FROM t_student WHERE Score >= @Score' EXEC SP_EXECUTESQL @sql,N'@Nums INT OUT,@Score INT',@OUT_Nums OUTPUT,@IN_Score SELECT @OUT_Nums AS '人數' 執行結果: 需要注意的是: 1、要求動態Sql和動態Sql參數列表必須是NVARCHAR 2、動態Sql的參數列表與外部提供值的參數列表順序必需一致 3、一旦使用了 '@name = value' 形式之后,所有后續的參數就必須以 '@name = value' 的形式傳遞,比如: DECLARE @OUT_Nums INT,@IN_Score INT,@Sql NVARCHAR(MAX) SET @IN_Score = 90 SET @sql = 'SELECT @Nums=COUNT(1) FROM t_student WHERE Score >= @Score' EXEC SP_EXECUTESQL @stmt=@sql,@params=N'@Nums INT OUT,@Score INT',@Nums=@OUT_Nums OUTPUT,@Score=@IN_Score SELECT @OUT_Nums AS '人數' 通過上面的例子已經很清晰的表明了,在執行動態SQL 語句的時候,EXEC 和 SP_EXECUTESQL 的區別了,來總結一下: 1、 性能: 官方描述:sp_executesql stmt 參數中的 Transact-SQL 語句或批處理在執行 sp_executesql 語句時才編譯。隨后,將編譯 stmt 中的內容,并將其作為執行計劃運行。該執行計劃獨立于名為 sp_executesql 的批處理的執行計劃。sp_executesql 批處理不能引用調用 sp_executesql 的批處理中聲明的變量。sp_executesql 批處理中的本地游標或變量對調用 sp_executesql 的批處理是不可見的。對數據庫上下文所做的更改只在 sp_executesql 語句結束前有效。如果只更改了語句中的參數值,則 sp_executesql 可用來代替存儲過程多次執行 Transact-SQL 語句。因為 Transact-SQL 語句本身保持不變,僅參數值發生變化,所以 SQL Server 查詢優化器可能重復使用首次執行時所生成的執行計劃。 說通俗一點就是:如果用 EXEC 執行一條動態 SQL 語句,由于每次傳入的參數不一樣,所以每次生成的 @sql 就不一樣,這樣每執行一次SQL SERVER 就必須重新將要執行的動態 Sql 重新編譯一次 。但是SP_EXECUTESQL 則不一樣,由于將數值參數化,要執行的動態 Sql 永遠不會變化,只是傳入的參數的值在變化,那每次執行的時候就不用重新編譯,速度和效率自然有所提升。 2、從上面的例子我們已經能夠看出 SP_EXECUTESQL 命令比 EXEC 命令更靈活,因為它提供一個接口,該接口及支持輸入參數也支持輸出參數。 3、EXEC 執行純動態SQL,執行時可能無法使用預編譯的執行計劃,關鍵是不安全,可以導致 SQL 注入 ,而 SP_EXECUTESQL 執行參數化動態 SQL ,執行時能使用預編譯的執行計劃,而且保存存儲過程時就可以確定可以使用的預編譯的執行計劃,而且最重要的是“安全”,天然免疫SQL 注入 轉自https://www.cnblogs.com/lxblog/archive/2013/01/14/2859828.html 該文章在 2025/2/10 16:02:54 編輯過 |
關鍵字查詢
相關文章
正在查詢... |