1、EXEC命令的括號中只允許包含一個字符串變量,或者一個 字符串文本,或者字符串變量與字符串文本的串聯。不能再括號中使用函數或CASE表達式,如下面嘗試在括號中調用QUOTENAME函數以引用對象名稱,運行將失敗:
1: DECLARE @schemaname NVARCHAR(255),@tablename NVARCHAR(128)
2: SET @schemaname='dbo'
3: SET @tablename='Order Details'
4:
5: EXEC (N'SELECT COUNT(*) FROM '+QUOTENAME(@schemaname)+N'.'+QUOTENAME(@tablename)+N';')
上述代碼將會產生如下錯誤:
消息 102,級別 15,狀態 1,第 5 行
'QUOTENAME' 附近有語法錯誤。
SQL Server 分析和編譯時間:
CPU 時間 = 0 毫秒,佔用時間 = 0 毫秒。
SQL Server 執行時間:
CPU 時間 = 0 毫秒,佔用時間 = 0 毫秒。
所以做好的方法是把代碼構造到一個變量中,這樣就不會受限制了,然後再把該變量作爲EXEC命令的輸入參數,就像這樣:
1: DECLARE @schemaname NVARCHAR(255) ,
2: @tablename NVARCHAR(128) ,
3: @sql NVARCHAR(MAX)
4: SET @schemaname = 'dbo'
5: SET @tablename = 'Order Details'
6: SET @sql = N'SELECT COUNT(*) FROM ' + QUOTENAME(@schemaname) + N'.'
7: + QUOTENAME(@tablename) + N';'
8: EXEC (@sql)
2、EXEC不提供接口。EXEC(<string>)不提供接口。它唯一的輸入就是包含你要調用代碼的字符串。動態批處理不能訪問在調用批處理中定義的局部變量。如下面代碼嘗試訪問定義在調用批處理中的變量將失敗。
1: DECLARE @i INT
2: SET @i = 10248
3:
4: DECLARE @sql NVARCHAR(MAX)
5:
6: SET @sql = 'SELECT * FROM dbo.Orders WHERE OrderID=@i;'
7: EXEC(@sql)
將產生如下錯誤:
消息 137,級別 15,狀態 2,第 1 行
必須聲明標量變量 "@i"。
使用EXEC時,如果想訪問變量,必須把變量內容串聯到動態構建的 代碼字符串中。
DECLARE @i INT
SET @i = 10248
DECLARE @sql NVARCHAR(MAX)
SET @sql = 'SELECT * FROM dbo.Orders WHERE OrderID='
+ CAST(@i AS NVARCHAR(10)) + ';'
EXEC(@sql)
這樣就沒有問題了。
如果一個變量包含字符串,把該變量的內容串聯到代碼將會導致安全風險(SQL注入),爲了避免SQL注入,可以吧字符串大小限制爲所需的最小長度。當然,實際中這種情況根本不需要動態SQL直接執行SQL語句就可以,這個示例只是爲了演示。
串聯變量的內容存在性能方面的弊端,SQL Server將爲每個唯一的查詢字符串創建新的即席執行計劃,即使查詢模式相同也是這樣的。爲演示這一點,先清空緩存中的執行計劃。
DBCC FREEPROCCACHE
1: SELECT cacheobjtype ,
2: objtype ,
3: usecounts ,
4: sql
5: FROM sys.syscacheobjects
6: WHERE sql NOT LIKE '%cache%'
7: AND sql NOT LIKE '%sys.%'
得到查詢結果:
cacheobjtype objtype usecounts sql
Compiled Plan Adhoc 1 SELECT * FROM dbo.Orders WHERE OrderID=10250;
Compiled Plan Adhoc 1 SELECT * FROM dbo.Orders WHERE OrderID=10248;
Compiled Plan Prepared 3 (@1 smallint)SELECT * FROM [dbo].[Orders] WHERE [OrderID]=@1
Compiled Plan Adhoc 4 SET STATISTICS IO ON SET STATISTICS TIME ON
Compiled Plan Adhoc 1 SELECT * FROM dbo.Orders WHERE OrderID=10249;
Compiled Plan Adhoc 4 SET STATISTICS IO OFF SET STATISTICS TIME OFF
EXEC除了不支持動態批處理中的輸入參數外,也不支持輸出參數。默認情況下,EXEC把查詢輸出返回給調用者。如果你想把輸出結果返回給調用批處理中的變量,事情就沒那麼簡單了,爲此,你需要使用INSERT EXEC把輸出插入到一個目的表,然後再從該表中取值,賦給該變量,就像這樣:
1: DECLARE @schemaname NVARCHAR(128) ,
2: @tablename NVARCHAR(128) ,
3: @colname NVARCHAR(128) ,
4: @sql NVARCHAR(MAX) ,
5: @cnt INT
6:
7: SET @schemaname = 'dbo'
8: SET @tablename = 'Orders'
9: SET @colname = 'CustomerID'
10:
11: SET @sql = N'SELECT COUNT(DISTINCT ' + QUOTENAME(@colname) + ') FROM '
12: + QUOTENAME(@schemaname) + N'.' + QUOTENAME(@tablename) + N';'
13:
14: CREATE TABLE #T1 ( cnt INT )
15: INSERT INTO #T1
16: EXEC ( @sql
17: )
18: SELECT @cnt = cnt
19: FROM #T1
20: SELECT @cnt
21: DROP TABLE #T1
3、在SQL Server2000中串聯變量值時,EXEC比sp_executesql多一個優勢,它支持更長的代碼,儘管技術上sp_executesql的輸入代碼字符串是NTEXT類型的,但你一般是在局部變量中構造代碼字符串。而你又不能用大型對象類型聲明局部變量,所以,實際上在sp_executesql中執行的查詢字符串被限制爲Unicode字符串(NVARCHAR)支持的最大長度4000,而EXEC支持常規字符串(VARCHAR)允許最大8000個字符。另外EXEC還支持一個特殊的功能,它允許你在括號中串聯多個變量,每個變量都支持8000個字符的長度。
在SQL Server2005中,就不用這麼糾結了,因爲可以爲EXEC命令提供一個VARCHAR(MAX)或NVARCHAR(MAX)的變量作爲輸入,輸入字符串可以達到2GB大小