Gộp nhiều hàng thành một hàng với GROUP_CONCAT() trong MySQL
Hàm GROUP_CONCAT() nối chuỗi các giá trị trong nhóm (GROUP BY) thành một chuỗi, phân cách bằng dấu phân cách tùy chọn. Dùng để "gộp hàng" theo khóa chung.
Ví dụ minh họa
Tạo bảng DemoTable734:
mysql> CREATE TABLE DemoTable734 (
Id INT,
Name VARCHAR(100)
);
Query OK, 0 rows affected (0.73 sec)
Chèn dữ liệu (Name trùng lặp, Id khác nhau):
mysql> INSERT INTO DemoTable734 VALUES(101, 'John'); Query OK, 1 row affected (0.23 sec) mysql> INSERT INTO DemoTable734 VALUES(102, 'John'); Query OK, 1 row affected (0.22 sec) mysql> INSERT INTO DemoTable734 VALUES(103, 'Chris'); Query OK, 1 row affected (0.14 sec) mysql> INSERT INTO DemoTable734 VALUES(104, 'Chris'); Query OK, 1 row affected (0.20 sec) mysql> INSERT INTO DemoTable734 VALUES(104, 'Chris'); Query OK, 1 row affected (0.13 sec)
Xem dữ liệu gốc (5 hàng):
mysql> SELECT * FROM DemoTable734;
+------+-------+ | Id | Name | +------+-------+ | 101 | John | | 102 | John | | 103 | Chris | | 104 | Chris | | 104 | Chris | +------+-------+ 5 rows in set (0.00 sec)
Gộp theo Name, nối Id distinct bằng dấu phẩy:
mysql> SELECT Name, GROUP_CONCAT(DISTINCT Id SEPARATOR ',') FROM DemoTable734 GROUP BY Name;
Kết quả (2 hàng, Id đã gộp):
+-------+-----------------------------------------+ | Name | GROUP_CONCAT(DISTINCT Id SEPARATOR ',') | +-------+-----------------------------------------+ | Chris | 103,104 | | John | 101,102 | +-------+-----------------------------------------+ 2 rows in set (0.04 sec)
Các tùy chọn GROUP_CONCAT
| Tùy chọn | Cú pháp | Mặc định |
|---|---|---|
| Phân cách | SEPARATOR ',' | ',' |
| Loại trùng | DISTINCT | Giữ trùng (ALL) |
| Sắp xếp trong nhóm | ORDER BY Id ASC | Thứ tự không xác định |
| Giới hạn độ dài | group_concat_max_len (system var) | 1024 bytes |
Ví dụ đầy đủ tùy chọn
SELECT
Name,
GROUP_CONCAT(DISTINCT Id ORDER BY Id ASC SEPARATOR '; ') AS Ids
FROM DemoTable734
GROUP BY Name;
Tăng giới hạn độ dài kết quả
-- Session level SET SESSION group_concat_max_len = 1000000; -- Global (cần SUPER privilege, persistent qua restart cần config file) SET GLOBAL group_concat_max_len = 1000000;
Ứng dụng thực tế
- Danh sách tag/categories của bài viết:
GROUP_CONCAT(tag_name) - Email nhận CC:
GROUP_CONCAT(email SEPARATOR ';') - JSON array thủ công:
CONCAT('[', GROUP_CONCAT(JSON_OBJECT('id', id, 'name', name)), ']') - Pivot ngược (rows → columns) kết hợp CASE WHEN
Lưu ý
- Kết quả bị cắt nếu vượt
group_concat_max_len(mặc định 1024 bytes) DISTINCTtăng chi phí CPU/bộ nhớ- MySQL 8.0+: cân nhắc
JSON_ARRAYAGG()cho output JSON chuẩn