問題現象
需求:依 de.status 排序,但當 status=2 且 結束時間 - 開始時間 > 0 時,需調整排序優先級。DECODE 單一值比較,無法直接處理複合條件。
DECODE 限制
-- DECODE 只能做單值等值比較
ORDER BY DECODE(de.status, 2, 1, 3, 2, 1, 3, 4, 4)
-- 無法加入:AND (de.end_time - de.start_time) > 0
解決方案:CASE WHEN 多條件排序
ORDER BY
CASE
WHEN de.status = 2 AND (de.end_time - de.start_time) > 0 THEN 1 -- 最高優先
WHEN de.status = 2 THEN 2
WHEN de.status = 3 THEN 3
WHEN de.status = 1 THEN 4
WHEN de.status = 4 THEN 5
ELSE 99
END,
de.start_time -- 次要排序:開始時間
完整查詢範例
SELECT de.*
FROM delivery de
ORDER BY
CASE
WHEN de.status = 2 AND (de.end_time - de.start_time) > 0 THEN 1
WHEN de.status = 2 THEN 2
WHEN de.status = 3 THEN 3
WHEN de.status = 1 THEN 4
WHEN de.status = 4 THEN 5
ELSE 99
END,
de.created_at DESC;
CASE WHEN vs DECODE 對比
| 特性 | DECODE | CASE WHEN |
| 語法標準 | Oracle 專有 | ANSI SQL 標準 (跨資料庫) |
| 比較類型 | 僅等值比較 | 支援任意布林表達式 (<, >, BETWEEN, LIKE, AND/OR) |
| 多條件 | 不支援 (需嵌套) | 原生支援 |
| 可讀性 | 簡單情況較簡潔 | 複雜邏輯結構清晰 |
| 效能 | 相同 (優化器同等對待) | 相同 |
進階:動態排序欄位
ORDER BY
CASE :sort_by
WHEN 'status_priority' THEN
CASE
WHEN de.status = 2 AND (de.end_time - de.start_time) > 0 THEN 1
WHEN de.status = 2 THEN 2
ELSE 99
END
WHEN 'created_desc' THEN de.created_at
WHEN 'amount_asc' THEN de.amount
ELSE de.id
END DESC;
常見錯誤
| 錯誤 | 修正 |
| CASE 回傳資料型別不一致 | 所有 THEN/ELSE 回傳相同型別 (數字/字串/日期) |
| 忘記 END | 每個 CASE 必須以 END 結束 |
| NULL 值排序異常 | 加入 NULLS FIRST/LAST 或 NVL(col, 默認值) |