函數定義
返回結果集中每組非 NULL 值的連接字符串。需配合 GROUP BY 使用,否則整個結果集視為一組。
完整語法
GROUP_CONCAT(
[DISTINCT] expr
[ORDER BY {unsigned_integer | col_name | expr} [ASC|DESC] [, ...]]
[SEPARATOR str_val]
)
核心參數詳解
| 子句 | 作用 | 默認值 | 示例 |
| DISTINCT | 去除重複值 | 不去重 | GROUP_CONCAT(DISTINCT city) |
| ORDER BY | 組內排序 | 無序 (依存儲順序) | GROUP_CONCAT(name ORDER BY id DESC) |
| SEPARATOR | 分隔符 | ',' (逗號) | GROUP_CONCAT(tag SEPARATOR '|') |
分組邏輯驗證實驗
CREATE TABLE players (id INT, name VARCHAR(20), town VARCHAR(20));
INSERT INTO players VALUES
(1,'Alice','北京'),(2,'Bob','長沙'),(3,'Cindy','北京');
-- 1. 無 GROUP BY:整表一組
SELECT GROUP_CONCAT(town) FROM players;
-- 結果: 北京,長沙,北京
-- 2. GROUP BY town:按城市分組
SELECT GROUP_CONCAT(name) FROM players GROUP BY town;
-- 結果:
-- town=北京: Alice,Cindy
-- town=長沙: Bob
-- 3. 多列 GROUP_CONCAT
SELECT GROUP_CONCAT(name, ':', town) FROM players GROUP BY town;
-- 結果: Alice:北京,Cindy:北京 / Bob:長沙
關鍵限制:group_concat_max_len
-- 查看默認 (1024 字節)
SHOW VARIABLES LIKE 'group_concat_max_len';
-- 會話級調大
SET SESSION group_concat_max_len = 1024000; -- 1MB
-- 全局永久 (my.cnf)
[mysqld]
group_concat_max_len = 1024000
-- 超長行為:截斷 + Warning (Code 1260)
SHOW WARNINGS;
-- | Warning | 1260 | 1 line(s) were cut by GROUP_CONCAT() |
實戰場景與優化
場景一:標籤聚合 (文章-標籤多對多)
SELECT
a.id, a.title,
GROUP_CONCAT(t.name ORDER BY t.id SEPARATOR ',') AS tags
FROM article a
LEFT JOIN article_tag at ON a.id = at.article_id
LEFT JOIN tag t ON at.tag_id = t.id
GROUP BY a.id, a.title;
場景二:報表導出 (部門-員工明細)
SELECT
d.name AS dept,
GROUP_CONCAT(CONCAT(e.name,'(',e.emp_no,')') ORDER BY e.hire_date SEPARATOR '; ') AS employees
FROM dept d
LEFT JOIN emp e ON d.id = e.dept_id
GROUP BY d.id, d.name;
場景三:條件聚合 (只聚合啟用狀態)
SELECT
user_id,
GROUP_CONCAT(CASE WHEN status=1 THEN role_name END ORDER BY role_id SEPARATOR ',') AS active_roles
FROM user_role
GROUP BY user_id;
性能優化建議
| 優化點 | 說明 |
| 索引支撐 GROUP BY | 確保 GROUP BY 列有索引,避免臨時表+文件排序 |
| 避免 DISTINCT | DISTINCT 需額外排序/哈希去重,業務允許則不加 |
| 控制結果集大小 | 單行超長影響網絡傳輸、內存,必要時 SUBSTRING_INDEX 截取前 N 個 |
| 大數據量分頁 | 應用層分頁查詢,每頁 GROUP_CONCAT,而非全量聚合 |
跨數據庫對比
| 數據庫 | 對應函數 | 語法差異 |
| MySQL | GROUP_CONCAT | SEPARATOR、ORDER BY 靈活 |
| PostgreSQL | STRING_AGG | STRING_AGG(expr, delimiter) ORDER BY ... |
| Oracle | LISTAGG | LISTAGG(expr, delimiter) WITHIN GROUP (ORDER BY ...) |
| SQL Server | STRING_AGG (2017+) | STRING_AGG(expr, delimiter) [WITHIN GROUP (ORDER BY ...)] |
| SQLite | GROUP_CONCAT | 語法與 MySQL 幾乎相同 |
避坑清單
- 忘記 GROUP BY:全表聚合成一行,非預期
- NULL 值被忽略:GROUP_CONCAT 自動跳過 NULL,如需保留用
IFNULL(expr,'NULL')
- 超長截斷無報錯:只產生 Warning,應用層需檢查長度或調大參數
- SEPARATOR 含特殊字符:如
',' 在 CSV 中衝突,建議用 '|' 或 '\t'
- 字符集不一致:表/連接/結果字符集不一致導致亂碼,統一 utf8mb4
GROUP_CONCAT 是 MySQL 最實用的聚合函數之一,**掌握「分組+排序+分隔符+長度控制」四要素**,能優雅解決「一對多扁平化輸出」90% 的場景。