CONCAT(str1, str2, ...) 有一個「毒藥」特性:**任一參數為 NULL,整體返回 NULL**。這在電話號碼拼接 (區號 + 號碼)、地址組裝、全名生成等場景極易踩坑。本文提供 IFNULL、COALESCE、CONCAT_WS 三大解決方案,並對比適用場景與效能。
SELECT CONCAT(isdcode, telephone) FROM gb_customer;
-- 若 isdcode 為 NULL,即使 telephone 有值,結果仍為 NULL
-- IFNULL: 兩參數,第一個非 NULL 返回第一個,否則返回第二個
SELECT CONCAT(IFNULL(isdcode, ''), telephone) FROM gb_customer;
-- COALESCE: 多參數,返回第一個非 NULL 值 (標準 SQL,可移植)
SELECT CONCAT(COALESCE(isdcode, ''), telephone) FROM gb_customer;
-- 語法:CONCAT_WS(separator, str1, str2, ...)
-- 自動跳過 NULL 參數,不跳過空字符串 ''
SELECT CONCAT_WS('', isdcode, telephone) FROM gb_customer;
-- 等價於 CONCAT(IFNULL(isdcode,''), IFNULL(telephone,'')) 但更簡潔
-- 實際業務常需分隔符
SELECT CONCAT_WS('-', isdcode, telephone); -- 區號-號碼,自動處理 NULL
SELECT
CONCAT(
CASE WHEN isdcode IS NULL OR isdcode = '' THEN '' ELSE isdcode END,
telephone
) FROM gb_customer;
| 方案 | 語法複雜度 | NULL 處理 | 空串 '' 處理 | 效能 | 適用場景 |
|---|---|---|---|---|---|
| IFNULL/COALESCE | 低 | 替換為指定值 | 保留空串 | 極快 | 通用、需指定預設值 |
| CONCAT_WS | 極低 | **自動跳過** | 保留空串 (視為有值) | 極快 (內建優化) | 拼接多字段、需分隔符、容忍空串 |
| CASE WHEN | 高 | 完全可控 | 可視為缺省 | 稍慢 | 複雜業務規則、空串也視為無 |
-- 列為 NULL 時顯示預設值
SELECT IFNULL(col1, 'default-value'), col2 FROM test;
-- 空串或 NULL 統一替換
SELECT
col1,
CASE WHEN col2 = '' OR col2 IS NULL THEN 'default-value' ELSE col2 END AS col2_fixed
FROM test;
SELECT CONCAT(IFNULL(a,''), IFNULL(b,'')) FROM t; -- ~1.2s
SELECT CONCAT_WS('', a, b) FROM t; -- ~1.1s (略快)
SELECT CONCAT(a, b) FROM t WHERE a IS NOT NULL; -- ~0.9s (但過濾掉 NULL 行)
差異微小,**優先選擇可讀性最高的 CONCAT_WS**。
最佳實踐: 字符串拼接**默認使用
CONCAT_WS('', ...)**,語意清晰「空值不參與拼接」、無需逐個包裹IFNULL、支援任意多參數、內建優化。僅在「空字符串也應視為缺省」或「需自定義預設值」時改用CASE WHEN或COALESCE。