MySQL IN (2,1,3) 查出的資料順序預設依主鍵或索引排序,而非 IN 列表順序。若業務要求「完全按照列表順序輸出」,ORDER BY FIND_IN_SET() 是最簡潔、效能可接受的解法。本文詳細示範用法、原理與效能注意事項。
SELECT * FROM users WHERE id IN (2, 1, 3);
-- 預設輸出:id 1, 2, 3(按主鍵排序)
-- 期望輸出:id 2, 1, 3(按 IN 列表順序)
SELECT *
FROM users
WHERE id IN (2, 1, 3)
ORDER BY FIND_IN_SET(id, '2,1,3');
結果:精準依 2, 1, 3 順序輸出。
FIND_IN_SET(str, strlist):在以逗號分隔的字串 strlist 中尋找 str,回傳位置(1-based),找不到回傳 0ORDER BY 依此位置值排序,自然符合列表順序strlist 不可含空格,'2, 1, 3' 會導致匹配失敗| 資料量 | 建議方案 | 說明 |
|---|---|---|
| < 1 萬筆 | FIND_IN_SET | 簡單直觀,全表掃描可接受 |
| 10 萬~百萬 | FIELD() 函式 | ORDER BY FIELD(id, 2,1,3) 內部優化較好,不需字串解析 |
| > 百萬 | 應用層排序 / 臨時表 | 避免 SQL 排序壓力,或建立映射表 JOIN |
FIELD() 替代方案(推薦)SELECT *
FROM users
WHERE id IN (2, 1, 3)
ORDER BY FIELD(id, 2, 1, 3);
FIELD(str, str1, str2, ...) 直接接受多參數,無字串解析開銷FIND_IN_SET(位置索引),NULL 值回傳 0 排最前,需留意PHP 範例:
$ids = [2, 1, 3];
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$orderField = 'FIELD(id, ' . implode(',', $ids) . ')';
$sql = "SELECT * FROM users WHERE id IN ($placeholders) ORDER BY $orderField";
$stmt = $pdo->prepare($sql);
$stmt->execute($ids);
FIND_IN_SET 最省事FIELD() 首選下次遇到「按指定 ID 順序輸出」需求,直接上 FIELD(),優雅又高效。