GROUP BY gom các dòng cùng giá trị thành nhóm, mỗi nhóm trả về một dòng — giống như "đếm số đơn theo từng danh mục".
Quy tắc bắt buộc: mọi cột trong SELECT phải hoặc nằm trong GROUP BY, hoặc là hàm tổng hợp. SELECT dept, name, COUNT(*) GROUP BY dept báo lỗi vì name không thỏa (PostgreSQL chặt; MySQL dễ dãi hơn).
SELECT category, COUNT(*) AS total, AVG(price) AS avg_price
FROM products GROUP BY category ORDER BY total DESC;Khi làm báo cáo cần thêm dòng tổng phụ/tổng chung:
- ROLLUP: thêm subtotal theo cấp + grand total — GROUP BY ROLLUP(dept, team).
- CUBE: subtotal cho mọi tổ hợp chiều — GROUP BY CUBE(dept, year).
- GROUPING SETS: tự chỉ định đúng các nhóm cần — linh hoạt hơn ROLLUP/CUBE.
Lưu ý: gom theo cột không có index sẽ quét toàn bảng + sort — cân nhắc thêm index nếu chạy thường xuyên.
GROUP BY collapses rows with the same value into groups, one row per group — like "count orders per category".
Mandatory rule: every column in SELECT must either be in GROUP BY or be an aggregate function. SELECT dept, name, COUNT(*) GROUP BY dept errors because name qualifies as neither (PostgreSQL is strict; MySQL is lenient).
SELECT category, COUNT(*) AS total, AVG(price) AS avg_price
FROM products GROUP BY category ORDER BY total DESC;For reports that need subtotals/grand totals:
- ROLLUP: adds per-level subtotals + a grand total — GROUP BY ROLLUP(dept, team).
- CUBE: subtotals for every combination of dimensions — GROUP BY CUBE(dept, year).
- GROUPING SETS: specify exactly which groupings you want — more flexible than ROLLUP/CUBE.
Pitfall: grouping on a non-indexed column scans the whole table + sorts — consider an index if it runs often.