當須要根據外部輸入的參數來決定要執行的SQL語句時,經常須要動態來構造SQL查詢語句,我的以爲用得比較多的地方就是分頁存儲過程和執行搜索查詢的SQL語句。一個比較通用的分頁存儲過程,可能須要傳入表名,字段,過濾條件,排序等參數,而對於搜索的話,可能要根據搜索條件判斷來動態執行SQL語句。
在SQL Server中有兩種方式來執行動態SQL語句,分別是exec和sp_executesql。sp_executesql相對而言具備更多的優勢,它提供了輸入輸出接口,能夠將輸入輸出變量直接傳遞到SQL語句中,而exec只能經過拼接的方式來實現。 還有一個優勢就是sp_executesql,可以重用執行計劃,這就大大提升了執行的性能。因此通常狀況下建議選擇sp_executesql來執行動態SQL語句。
使用sp_executesql須要注意的一點就是,它後面執行的SQL語句必須是Unicode編碼的字符串,因此在聲明存儲動態SQL語句的變量時必須聲明爲nvarchar類型(若是不知道SQL語句有多長,能夠直接用nvarchar(max)類型),不然在執行的時候會報「過程須要類型爲 'ntext/nchar/nvarchar' 的參數 '@statement'」的錯誤,若是是使用sp_executesql直接執行SQL語句,則必須在前面加上大寫字母N,以代表後面的字符串是使用Unicode類型編碼的。
下面來看看幾種動態執行SQL語句的狀況
1.普通SQL語句
exec('select * from Student') exec sp_executesql N'select * from Student'--此處必定要加上N,不然會報錯
2.帶參數的SQL語句html
declare @sql nvarchar(1000) declare @userId varchar(100) set @userId='0001' set @sql='select * from Student where UserID='''+@userId+'''' exec(@sql)
declare @sql nvarchar(1000) declare @userId varchar(100) set @userId='0001' set @sql=N'select * from Student where UserID=@userId' exec sp_executesql @sql,N'@userId varchar(100)',@userId
從這個例子中能夠看出使用sp_executesql能夠直接將參數寫在sql語句中,而exec須要使用拼接的方式,這在必定程度上能夠防止SQL注入,所以sp_executesql擁有更高的安全性。另外須要注意的是,存儲sql語句的變量必須聲明爲nvarchar類型的。sql
3.帶輸出參數的SQL語句安全
create procedure [dbo].[sp_GetNameByUserId] ( @userId varchar(100), @userName varchar(100) output ) as begin declare @sql nvarchar(1000) set @sql=N'select @userName=UserName from Student where UserId=@userId' exec sp_executesql @sql,N'@userId varchar(100),@userName varchar(100) output',@userId,@userName output select @userName end
原文連接性能