| 函數 | 語法 | 行為 | NULL 處理 | 典型場景 |
|---|---|---|---|---|
CONCAT | CONCAT(str1, str2, ...) | 直接拼接所有參數 | 任一參數為 NULL → 結果為 NULL | 簡單拼接、構建動態 SQL |
CONCAT_WS | CONCAT_WS(sep, str1, str2, ...) | 用分隔符拼接,跳過 NULL | 自動忽略 NULL 參數 | 路徑拼接、CSV 生成、標籤聚合 |
SELECT CONCAT('My', 'S', 'QL'); -- 'MySQL'
SELECT CONCAT('My', NULL, 'QL'); -- NULL
SELECT CONCAT(14.3); -- '14.3' (數字隱式轉字符串)
SELECT CONCAT(CAST(100 AS CHAR), 'abc'); -- '100abc' 顯式轉型避免二進制字符串
二進制字符串陷阱:若任一參數為二進制字符串(如 BLOB、BIT、未轉型的數字),結果為二進制字符串,可能導致字符集比較異常。建議顯式 CAST(... AS CHAR)。
-- 路徑拼接(自動處理 NULL、不產生雙分隔符)
UPDATE users SET home_dir = CONCAT_WS('/', '/data/disk1', part, user) WHERE id=1;
-- 結果:/data/disk1/part1/user1 (若 part 為 NULL → /data/disk1/user1)
-- 標籤聚合(配合 GROUP_CONCAT)
SELECT user_id, CONCAT_WS(',', tag1, tag2, tag3) AS tags FROM user_tags;
-- 動態構建 WHERE IN 列表
SET @ids = CONCAT_WS(',', 1, 2, NULL, 4); -- '1,2,4'
PREPARE stmt FROM CONCAT('SELECT * FROM t WHERE id IN (', @ids, ')');
CONCAT('a', NULL, 'b') 返回 NULL。解決:CONCAT('a', IFNULL(col, ''), 'b') 或改用 CONCAT_WS('', 'a', col, 'b')(空分隔符)。
拼接不同字符集列(如 utf8mb4 + latin1)會報 Illegal mix of collations。解決:CONCAT(CONVERT(col1 USING utf8mb4), CONVERT(col2 USING utf8mb4)) 或統一表字符集。
max_allowed_packet 截斷拼接超長字符串(> 4MB 默認)會靜默截斷並產生警告。檢查 SHOW WARNINGS,調大 max_allowed_packet 或分塊處理。
CONCAT(1e10) → '10000000000.0' 而非 '10000000000'。解決:CAST(num AS CHAR) 或 FORMAT(num, 0)。
-- 安全構建 IN 列表(防注入)
SET @safe_ids = CONCAT_WS(',',
(SELECT QUOTE(id) FROM tmp_ids WHERE batch=1)
);
PREPARE s FROM CONCAT('SELECT * FROM orders WHERE id IN (', @safe_ids, ')');
-- 模擬 JSON_OBJECT(5.7- 無原生函數時)
SELECT CONCAT('{"name":"', REPLACE(name, '"', '\\"'), '","age":', age, '}') AS json_str FROM users;
CONCAT/CONCAT_WS 都是 CPU 密集型,避免在大結果集(>10萬行)的 SELECT 列表中濫用。full_path VARCHAR(500) GENERATED ALWAYS AS (CONCAT_WS('/', base, sub)) STORED。CONCAT 適合無 NULL、無分隔符的簡單拼接;CONCAT_WS 是處理可選字段、路徑、列表拼接的「瑞士軍刀」,自動跳過 NULL、自帶分隔符。牢記 NULL 語義差異、字符集一致性、長度限制,即可在 SQL 中靈活高效地操作字符串。