GROUP_CONCAT(
[DISTINCT] expr
[ORDER BY {unsigned_integer | col_name | expr} [ASC | DESC]]
[SEPARATOR str_val]
)
DISTINCT:去重,默認不去重。ORDER BY:組內排序,支持列、表達式、位置序號。SEPARATOR:自定義分隔符,默認逗號 ','。-- 測試表
CREATE TABLE aa (id INT, name VARCHAR(10));
INSERT INTO aa VALUES (1,10),(1,20),(1,20),(2,20),(3,200),(3,500);
-- 1. 默認逗號分隔
SELECT id, GROUP_CONCAT(name) FROM aa GROUP BY id;
-- 1 | 10,20,20
-- 2 | 20
-- 3 | 200,500
-- 2. 自定義分隔符
SELECT id, GROUP_CONCAT(name SEPARATOR ';') FROM aa GROUP BY id;
-- 1 | 10;20;20
-- 3. 去重
SELECT id, GROUP_CONCAT(DISTINCT name) FROM aa GROUP BY id;
-- 1 | 10,20
-- 4. 組內降序
SELECT id, GROUP_CONCAT(name ORDER BY name DESC) FROM aa GROUP BY id;
-- 1 | 20,20,10
-- 3 | 500,200
默認 group_concat_max_len = 1024 字節,超截斷且無報錯。
-- 會話級調大(推薦,不影響其他連接)
SET SESSION group_concat_max_len = 102400; -- 100KB
-- 全局永久生效(需配置文件)
[mysqld]
group_concat_max_len = 102400
注意:結果仍受 max_allowed_packet 限制,極大聚合建議分批或應用層拼接。
SELECT
a.article_id,
a.title,
GROUP_CONCAT(t.tag_name ORDER BY t.tag_name SEPARATOR ',') AS tags
FROM article a
LEFT JOIN article_tag at ON a.article_id = at.article_id
LEFT JOIN tag t ON at.tag_id = t.tag_id
GROUP BY a.article_id, a.title;
SELECT GROUP_CONCAT(QUOTE(id)) FROM user WHERE status=1;
-- 輸出: '1','3','5','8'
-- 應用層拼接: SELECT * FROM order WHERE user_id IN (...)
SELECT
dept_id,
GROUP_CONCAT(CONCAT(emp_name, ':', salary) ORDER BY salary DESC SEPARATOR ';') AS emp_salary_list
FROM employee
GROUP BY dept_id;
| 問題 | 原因 | 對策 |
|---|---|---|
| 臨時表/文件排序 | GROUP BY 無索引、數據量大 | 建立 (group_col, sort_col) 聯合索引;適當增大 tmp_table_size/max_heap_table_size |
| 結果截斷無感知 | 超過 group_concat_max_len | 查詢前 SET SESSION group_concat_max_len=...;應用層檢查長度 |
| 內存暴漲 | 單組聚合極大(如萬級標籤) | 業務拆分:改用子表存儲、應用層分頁拼接 |
GROUP_CONCAT 是 MySQL 特有的強大聚合函數,善用 DISTINCT、ORDER BY、SEPARATOR 可完成「行轉列」、標籤聚合、動態 IN 列表等常見需求。核心注意點:調大 group_concat_max_len、警惕臨時表排序、極大聚合改用應用層處理。