業務中常需將 VARCHAR 存儲的數字字符串按數值大小排序/篩選/運算。MySQL 提供 CAST() 和 CONVERT() 兩大標準轉換函數。本文記錄語法、簽名差異、SIGNED/UNSIGNED 選擇、排序實戰、以及隱式轉換對比。
CAST(expr AS type) -- type 可選值: BINARY[(N)] CHAR[(N)] DATE DATETIME DECIMAL SIGNED [INTEGER] -- 有符號整數 UNSIGNED [INTEGER] -- 無符號整數 TIME
CONVERT(expr, type) -- 或字符集轉換語法: CONVERT(expr USING charset_name)
-- 表 cardserver,server_id VARCHAR(20) 存儲 '1','2','10','100' -- 字符串排序: '1', '10', '100', '2' (字典序) -- 數值排序: 1, 2, 10, 100 -- CAST 方案 SELECT server_id FROM cardserver WHERE game_id = 1 ORDER BY CAST(server_id AS SIGNED) DESC LIMIT 10; -- CONVERT 方案 SELECT server_id FROM cardserver WHERE game_id = 1 ORDER BY CONVERT(server_id, SIGNED) DESC LIMIT 10;
| 類型 | 範圍 | 適用場景 |
|---|---|---|
SIGNED / SIGNED INTEGER | -2147483648 ~ 2147483647 (INT) -9223372036854775808 ~ 9223372036854775807 (BIGINT) | 可能包含負數、通用業務 ID |
UNSIGNED / UNSIGNED INTEGER | 0 ~ 4294967295 (INT) 0 ~ 18446744073709551615 (BIGINT) | 純正數、自增 ID、雪花算法 ID、計數器 |
建議: ID類字段優先 UNSIGNED,擴大正數範圍、語義更清晰。
-- 1. 篩選數值範圍 SELECT * FROM gyzd_yysinfo WHERE CAST(yysid AS UNSIGNED) BETWEEN 100 AND 200; -- 2. 數值運算 SELECT CAST(price_str AS DECIMAL(10,2)) * quantity AS total FROM order_items; -- 3. 分組聚合 SELECT CAST(category_id AS UNSIGNED) AS cat_id, COUNT(*) FROM products GROUP BY cat_id; -- 4. 連接查詢類型對齊 (VARCHAR ID 關聯 INT ID) SELECT u.*, o.* FROM users u JOIN orders o ON CAST(u.user_id AS UNSIGNED) = o.user_id; -- 索引可能失效,見下文 -- 5. 字符集轉換 (CONVERT 專有) SELECT CONVERT(name USING utf8mb4) FROM legacy_table;
方案 適用場景 優缺點 虛擬生成列 + 索引 (5.7+) 頻繁按數值排序/篩選 ✅ 索引生效、✅ 寫入透明、❌ 佔額外空間 應用層轉換寫入 INT 列 新建表/重構 ✅ 根治、✅ 索引原生、❌ 需遷移 覆蓋索引包含原 VARCHAR 列 偶爾查詢、數據量小 ⚠️ 仍需 Filesort、但避免回表 按字符串排序兼容 (左補零) 固定長度數字 ID ✅ 索引生效、❌ 業務侵入性強 4.3 虛擬生成列最佳實踐 (5.7+)
需求 推薦方案 關鍵語法 臨時查詢排序/篩選 CAST/CONVERT CAST(col AS UNSIGNED)高頻查詢、大表 虛擬生成列 + 索引 GENERATED ALWAYS AS (CAST(col AS UNSIGNED)) VIRTUAL新表設計/重構 直接定義 INT/BIGINT UNSIGNED id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT字符集轉換 CONVERT ... USING CONVERT(col USING utf8mb4)核心提醒:
CAST/CONVERT解決「讀取時語義正確」,但**破壞索引**;高頻場景**必須**用虛擬生成列或重構列類型物質化數值,實現「存儲即索引、查詢即命中」。