SQL Server 2005 之前:`TOP` 只接受常數 (`TOP 10`),變數需動態 SQL 拼接 (`'SELECT TOP ' + @N + ' ...'`),導致計畫無法重用、注入風險、可讀性差。
關鍵:括號包裹變數 `TOP (@Variable)`
DECLARE @TopCount INT = 100;
SELECT TOP (@TopCount) *
FROM AdventureWorks.HumanResources.Employee
ORDER BY HireDate DESC;
此寫法:**計畫可重用**、**參數嗅探正常**、**防注入**、**可讀性高**。
當查詢條件結構動態 (如選填欄位、動態排序) 時,`sp_executesql` + 參數化 是黃金組合。
DECLARE @TopCount INT = 50;
DECLARE @TitlePattern NVARCHAR(100) = N'%Manager%'; -- 參數化 LIKE 模式
DECLARE @Gender NCHAR(1) = N'F'; -- 參數化等值
DECLARE @Sql NVARCHAR(MAX);
SET @Sql = N'
SELECT TOP (@TopCountPar)
BusinessEntityID, JobTitle, HireDate, Gender
FROM HumanResources.Employee
WHERE JobTitle LIKE @TitlePar
AND Gender = @GenderPar
ORDER BY HireDate DESC;';
-- 執行:參數定義 + 賦值分離,計畫緩存鍵包含參數化查詢文本
EXEC sp_executesql
@Sql,
N'@TopCountPar INT, @TitlePar NVARCHAR(100), @GenderPar NCHAR(1)',
@TopCountPar = @TopCount,
@TitlePar = @TitlePattern,
@GenderPar = @Gender;
| 維度 | EXEC (@String) | sp_executesql |
|---|---|---|
| 計畫重用 | 否 (每次字串不同產生新計畫) | **是** (參數化文本相同即重用) |
| 參數化 | 手動拼接字串 (注入風險、型別轉換錯誤) | **強型別參數傳遞** (安全、正確) |
| 效能 | 編譯開銷大、計畫緩存膨脹 | 編譯一次重用多次 |
| 變數作用域 | 需在字串內宣告/賦值 | 外部變數直接映射 |
`ORDER BY` 不支援參數化,需白名單驗證後拼接。
CREATE PROCEDURE dbo.GetTopEmployees
@TopCount INT = 20,
@SortColumn SYSNAME = 'HireDate', -- 白名單驗證
@SortOrder VARCHAR(4) = 'DESC' -- 'ASC'/'DESC'
AS
BEGIN
-- 白名單驗證
IF @SortColumn NOT IN (N'HireDate', N'BusinessEntityID', N'JobTitle', N'Gender')
THROW 50001, N'Invalid sort column.', 1;
IF @SortOrder NOT IN ('ASC', 'DESC')
THROW 50002, N'Invalid sort order.', 1;
DECLARE @Sql NVARCHAR(MAX) = N'
SELECT TOP (@TopCountPar) BusinessEntityID, JobTitle, HireDate, Gender
FROM HumanResources.Employee
ORDER BY ' + QUOTENAME(@SortColumn) + N' ' + @SortOrder + N';';
EXEC sp_executesql @Sql, N'@TopCountPar INT', @TopCountPar = @TopCount;
END
「TOP 參數化:加括號 `TOP (@Var)`;動態查詢:上 `sp_executesql`;ORDER BY:白名單拼接。」
這是 T-SQL 參數化編程的基石,亦是預存程序高效能、高安全性的前提。