-- id VARCHAR(20) 存純數字:'1','2','10','20','100' SELECT * FROM t ORDER BY id; -- 結果:1, 10, 100, 2, 20 (字典序/字符串排序) -- 期望:1, 2, 10, 20, 100 (數值排序)
SELECT * FROM t ORDER BY id + 0; SELECT * FROM t ORDER BY id * 1; SELECT * FROM t ORDER BY id - 0;
原理:MySQL 字符串參與數學運算 → 自動轉為 DOUBLE → 數值排序。
SELECT * FROM t ORDER BY CAST(id AS UNSIGNED); SELECT * FROM t ORDER BY CAST(id AS SIGNED);
SELECT * FROM t ORDER BY CONVERT(id, UNSIGNED INTEGER);
場景:按指定 ID 列表順序輸出 (如熱門商品置頂)。
-- $string_hot_pid = '100,50,200,10' SELECT p.*, FIND_IN_SET(p.id, '100,50,200,10') AS rank FROM products p WHERE p.id IN (100,50,200,10) ORDER BY rank;
FIND_IN_SET(str, strlist) -- strlist: 逗號分隔字符串 'a,b,c' -- 返回: str 在列表中的位置 (1-based),不存在返回 0 -- 優化: 若 str 為常量、strlist 為 SET 列 → 位運算優化 -- 限制: str 不能包含逗號,strlist 超長需調大 group_concat_max_len
| 方法 | 可用索引 | CPU 開銷 | 推薦場景 |
|---|---|---|---|
| ORDER BY id + 0 | ❌ 全表掃描 | 低 | 小表、臨時查詢 |
| ORDER BY CAST(id AS UNSIGNED) | ❌ 全表掃描 | 低 | 標準寫法、代碼可讀性 |
| 虛擬列 + 索引 | ✅ 索引排序 | 寫入額外開銷 | 大表、高頻排序查詢 |
ALTER TABLE t ADD COLUMN id_num INT GENERATED ALWAYS AS (CAST(id AS UNSIGNED)) STORED, ADD INDEX idx_id_num (id_num); -- 查詢自動走索引 SELECT * FROM t ORDER BY id_num;
'123abc' + 0 = 123 (截取前導數字) + Warning'001' + 0 = 1,排序正確但失去前導零語義CAST('-10' AS SIGNED) 正確,UNSIGNED 會變大正數DECIMAL(65,0) 或字符串左補零定長排序字符串排序與數值排序的本質差異在於 **比較器**。MySQL 提供多種轉型路徑,**選對工具、加上索引、修正建模**,徹底告別「10 排在 2 前面」的低級錯誤。