業務場景
一個教師 (userID) 對應多個班級 (Remark1),需查詢:教師 + 所有班級列表(逗號分隔)。
表結構示例
CREATE TABLE c_classuser_tab (
Id INT PRIMARY KEY AUTO_INCREMENT,
Classid INT,
Username VARCHAR(100),
Remark1 VARCHAR(100), -- 班級名
userID INT, -- 教師ID
userType INT,
KEY idx_classuser_complex (Classid, userID)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
核心語法
SELECT
Username,
GROUP_CONCAT(Remark1 ORDER BY Classid SEPARATOR ',') AS classes
FROM c_classuser_tab
WHERE userID = 123 AND userType = 1
GROUP BY Username, userID, userType;
GROUP_CONCAT 完整參數詳解
GROUP_CONCAT(
[DISTINCT] expr
[ORDER BY {unsigned_integer | col_name | expr} [ASC|DESC] [, ...]]
[SEPARATOR str_val]
)
| 子句 | 作用 | 示例 |
| DISTINCT | 去重 | GROUP_CONCAT(DISTINCT Remark1) |
| ORDER BY | 組內排序 | GROUP_CONCAT(Remark1 ORDER BY Classid DESC) |
| SEPARATOR | 自定義分隔符 (默認 ',') | GROUP_CONCAT(Remark1 SEPARATOR ';') |
關鍵限制:group_concat_max_len
-- 默認 1024 字節,超長截斷並產生 Warning
SHOW VARIABLES LIKE 'group_concat_max_len';
-- 會話級調大 (臨時)
SET SESSION group_concat_max_len = 1024000; -- 1MB
-- 全局永久調大 (my.cnf)
[mysqld]
group_concat_max_len = 1024000
性能優化建議
| 場景 | 優化方案 |
| 數據量大、分組多 | 確保 GROUP BY 列有索引 (如 idx_classuser_complex) |
| 結果集極大 | 分頁處理 / 應用層分批查詢 / 只取前 N 個 (SUBSTRING_INDEX) |
| 頻繁查詢 | 物化視圖 / 緩存 (Redis) 存儲合併結果 |
| 去重開銷大 | DISTINCT 需臨時表,評估是否業務允許不去重 |
進階技巧:條件合併 / 多字段合併
-- 條件合併:只合併狀態正常的班級
GROUP_CONCAT(CASE WHEN Status=1 THEN Remark1 END ORDER BY Classid SEPARATOR ',')
-- 多字段合併:班級名 + 學期
GROUP_CONCAT(CONCAT(Remark1, ':', Remark2) ORDER BY Classid SEPARATOR ';')
-- 限制數量:只取前 5 個班級
SUBSTRING_INDEX(GROUP_CONCAT(Remark1 ORDER BY Classid SEPARATOR ','), ',', 5)
對比:應用層合併 vs 數據庫合併
| 維度 | GROUP_CONCAT (DB層) | 應用層合併 |
| 網絡傳輸 | 少 (聚合後單行) | 多 (明細行全傳輸) |
| CPU 消耗 | DB 端 | App 端 |
| 靈活性 | 受 SQL 函數限制 | 完全可控 |
| 適用場景 | 結果集小、固定格式、報表導出 | 結果集大、複雜邏輯、需分頁 |
GROUP_CONCAT 是 MySQL 專有的聚合函數,**善用 ORDER BY、SEPARATOR、DISTINCT、長度調整**,能高效解決「一對多扁平化」展示需求。大數據量場景謹慎使用,優先考慮應用層分頁合併或緩存策略。