存儲過程中執行動態sql語句


存儲過程中執行動態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時,如果您想訪問變量,必須把變量內容串聯到動態構建的代碼字符串中,如:

SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) +
   'WHERE OrderID = '+CAST(@OrderID AS VARCHAR(10))+' ORDER BY ORDERID DESC'

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,如果想要將列名和表名動態參數化,不可以使用列名和表名來進行站位,

 
 


免責聲明!

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



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