存儲過程中執行動態sql語句
MSSQL提供了兩種方式:exec和sp_executesql
通常后者更有優勢,提供了輸入輸出接口,而exec沒有
sp_executesql的最大優點是能夠重用執行計划,大大提高了執行性能,所以盡量使用sp_executesql,它也更靈活
1 exec的使用
exec有兩種用法:執行一個存儲過程,另一種是執行一個動態的批處理
EXEC括號中只允許包含一個字符串變量,但是可以串聯多個變量,例如:
XEC('SELECT TOP('+ CAST(@TopCount AS VARCHAR(10)) +')* FROM '+
QUOTENAME(@TableName) +' ORDER BY ORDERID DESC');
這樣編譯器會報錯,編譯不通過
但可以這樣:EXEC(@sql+@sql2+@sql3);編譯就會通過
最好的辦法就是把代碼構造到一個變量中,然后再把該變量作為exec命名的輸入參數
exec的缺點是不能執行一個包含一個帶有變量的批處理
例如:
DECLARE @TableName VARCHAR(50),@Sql NVARCHAR(MAX),@OrderID INT; SET @TableName = 'Orders'; SET @OrderID = 10251; SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) + 'WHERE OrderID = @OrderID ORDER BY ORDERID DESC' EXEC(@sql);
使用EXEC時,如果您想訪問變量,必須把變量內容串聯到動態構建的代碼字符串中,如:
Exec除了不支持動態批處理中的輸入參數外,也不支持輸出參數,默認情況下,exec把查詢的輸出返回給調用者,
然而:如果要把輸出返回給調用批處理中的變量,就很麻煩,必須使用 insert exec語法把輸出插入到一個目標表,然后從這表中獲取值后賦值給該變量
DECLARE @TableName VARCHAR(50),@sql NVARCHAR(MAX),@OrderID INT ,@sql2 NVARCHAR(MAX); SET @TableName = 'Orders '; SET @OrderID = 10251; SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) + ' WHERE OrderID = '+CAST(@OrderID AS VARCHAR(50)) + ' ORDER BY ORDERID DESC' EXEC sp_executesql @sql
2 sp_executesql
sp_executesql 支持輸入參數也支持輸出參數,這個功能可以創建帶參數的查詢字符串
語法:代碼塊,參數聲明部分,參數賦值部分
EXEC sp_executesql
@stmt= <statement>,--類似存儲過程主體
@params = <params>, --類似存儲過程參數部分,聲明參數類型
<params assignment> --類似存儲過程調用,為參數賦值,參數值要和參數順序要一一對應,也可以通過為參數指明參數值的方式為其賦值
@stmt:是輸入的動態批處理,它可以引入輸入參數或者輸出參數,和存儲過程主體一樣,只不過它是動態的,而存儲過程是靜態的,也可以在存儲過程中使用sp_executesql
@params參數與定義輸入/輸出參數的存儲過程頭類似,實際上和存儲過程頭的語法完全一樣;
@<params assignment> 與調用存儲過程的EXEC部分類似。
其實@stmt,@params可以省略,那么exec sp_executesql的語法就可以簡寫成如下格式:
EXEC sp_executesql <statement>, <params>, <params assignment>
sq_executesql的另外一個強大的功能是:可以使用輸出參數為調用批處理的變量返回值,該功能可以避免用臨時表返回數據,定義和使用輸出參數的語法與存儲過程類似,需要在聲明時候指定 output 子句
以字母N為前綴標識字符串常量
總結:
1 使用exec sp_executesql效率要比exec要高,同一類型的語句,只需編譯一次即可,而exec執行幾次就編譯幾次
2 構造動態sql的where子句,也就是條件子句時,exec無法使用變量來進行占用, 需要將變量轉換成字符串,然后和動態sql進行拼接,這可能引起sql注入問題
如:SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +
' WHERE OrderID = '+CAST(@OrderID AS VARCHAR(50)) + ' ORDER BY ORDERID DESC'
而exec sp_executesql:則可以使用變量來進行站位,以后再給這個參數傳值的方式構造動態sql,這樣就避免了sql注入問題
SET @sql = 'SELECT * FROM '+@TableName + ' WHERE OrderID = @OID ORDER BY ORDERID DESC'
3 無論是exec還是exec sp_executesql,如果想要將列名和表名動態參數化,不可以使用列名和表名來進行站位,
