sp_executesql
@stmt NVARCHAR(MAX), -- 動態 SQL 批次 (必須 N'...')
@params NVARCHAR(MAX), -- 參數定義:N'@p1 type1, @p2 type2 OUT, ...'
@p1 = value1, @p2 = value2 OUT, ... -- 參數值對應
| 特性 | EXEC (@sql) | sp_executesql |
|---|---|---|
| 參數化 | 不支援 (字串拼接) | 原生支援輸入/輸出參數 |
| 計畫重用 | 每次不同字串 → 重新編譯 | 相同參數化樣板 → 重用計畫 |
| 注入風險 | 高 (拼接值) | 低 (參數化) |
| 輸出值 | 需用暫存表/全域變數 | 直接 OUTPUT 參數 |
DECLARE @sql NVARCHAR(MAX) = N'SELECT @cnt = COUNT(*) FROM emp WHERE id = @id;';
DECLARE @id VARCHAR(20) = '1';
DECLARE @cnt INT;
EXEC sp_executesql @sql,
N'@id VARCHAR(20), @cnt INT OUTPUT',
@id = @id, @cnt = @cnt OUTPUT;
PRINT @cnt; -- 正確輸出
EXEC sp_executesql @sql,
N'@cnt INT OUTPUT, @id VARCHAR(20)', -- 定義順序
@id = @id, @cnt = @cnt OUTPUT; -- 呼叫順序可不同,靠名稱對應
@id 查詢:SELECT usecounts, cacheobjtype, objtype, text FROM sys.dm_exec_cached_plans ... 可見 Prepared 物件 usecounts 累積。VARCHAR(20) vs NVARCHAR(20) 不匹配會隱含轉換或報錯。無法直接參數化 IN (@list),常見替代方案:
JOIN (SQL 2016+ STRING_SPLIT)。sp_executesql 是撰寫安全、高效能動態 SQL 的標準作法:**參數化 → 計畫重用 → 防注入**。務必養成 N'...'、型別精確、OUTPUT 雙向標示的習慣。大型動態查詢建議搭配 OPTION (RECOMPILE) 處理參數探查問題。