固定 ORDER BY Column 無法滿足「使用者自訂排序欄位/方向」的需求。本文示範如何在 ORDER BY 子句中嵌入 CASE 表達式,配合參數實現完全動態的多欄位、多方向排序,並封裝為預存程序供應用層呼叫。
-- 簡單 CASE
CASE @SortKey
WHEN 1 THEN ColumnA
WHEN 2 THEN ColumnB
ELSE ColumnC
END
-- 搜尋 CASE (支援複雜條件)
CASE
WHEN @SortKey = 1 AND @Dir = 'ASC' THEN ColumnA
WHEN @SortKey = 1 AND @Dir = 'DESC' THEN ColumnA DESC -- 錯誤!CASE 回傳值不可含 DESC
ELSE ColumnC
END
錯誤寫法:ORDER BY CASE WHEN @Dir='DESC' THEN Col END DESC — 語法錯誤
正確模式:雙層 CASE 或動態 SQL
CREATE PROCEDURE usp_GetCustomersDynamicSort
@SortColumn TINYINT = 1 -- 1=CompanyName, 2=ContactName, 3=ContactTitle
AS
SELECT CompanyName, ContactName, ContactTitle
FROM Customers
ORDER BY
CASE @SortColumn
WHEN 1 THEN CompanyName
WHEN 2 THEN ContactName
ELSE ContactTitle
END; -- 僅支援 ASC
CREATE PROCEDURE usp_GetCustomersFullDynamicSort
@SortColumn NVARCHAR(50) = 'CompanyName', -- 欄位名
@SortDir VARCHAR(4) = 'ASC' -- ASC/DESC
AS
BEGIN
SET NOCOUNT ON;
-- 防注入:白名單驗證
IF @SortColumn NOT IN ('CompanyName','ContactName','ContactTitle') SET @SortColumn = 'CompanyName';
IF @SortDir NOT IN ('ASC','DESC') SET @SortDir = 'ASC';
DECLARE @sql NVARCHAR(MAX) = N'
SELECT CompanyName, ContactName, ContactTitle
FROM Customers
ORDER BY ' + QUOTENAME(@SortColumn) + ' ' + @SortDir + ';';
EXEC sp_executesql @sql;
END
SELECT CompanyName, ContactName, ContactTitle
FROM Customers
ORDER BY
CASE WHEN @SortColumn=1 AND @SortDir='ASC' THEN CompanyName END ASC,
CASE WHEN @SortColumn=1 AND @SortDir='DESC' THEN CompanyName END DESC,
CASE WHEN @SortColumn=2 AND @SortDir='ASC' THEN ContactName END ASC,
CASE WHEN @SortColumn=2 AND @SortDir='DESC' THEN ContactName END DESC,
CASE WHEN @SortColumn=3 AND @SortDir='ASC' THEN ContactTitle END ASC,
CASE WHEN @SortColumn=3 AND @SortDir='DESC' THEN ContactTitle END DESC;
原理:非符合條件的 CASE 回傳 NULL,NULL 排在最前 (ASC) 或最後 (DESC),不影響結果順序。
| 方案 | 計畫重用 | 注入風險 | 支援度 | 適用場景 |
|---|---|---|---|---|
| 單層 CASE | ✅ 最佳 | 無 | 單欄位、固定 ASC | 簡單下拉選單排序 |
| 多層 CASE | ✅ 最佳 | 無 | 多欄位、雙方向 | 固定排序組合 (如 3 欄 × 2 向) |
| 動態 SQL | ⚠️ 需參數化 | 低 (白名單) | 完全動態 | 欄位名來自使用者輸入/設定表 |
動態排序導致計劃難以針對特定索引優化。可考慮:
INCLUDE 所有 SELECT 欄位OPTION (RECOMPILE) 讓參數嗅探生成最優計劃 (低頻呼叫)CASE 在 ORDER BY 中是實現「參數化排序欄位」的標準技巧;需「動態方向」時,多層 CASE 兼顧計劃重用與安全性;極少數完全動態場景才啟用動態 SQL,並嚴格白名單驗證。