Cả hai đều lọc, nhưng lọc ở thời điểm khác nhau — chìa khóa là thứ tự thực thi:
- WHERE chạy trước
GROUP BY: lọc từng dòng riêng lẻ. Không dùng được hàm tổng hợp (WHERE COUNT(*) > 5là lỗi cú pháp). - HAVING chạy sau
GROUP BY: lọc trên các nhóm. Dùng được hàm tổng hợp (HAVING COUNT(*) > 5).
Ví dụ:
sql
SELECT dept, COUNT(*) FROM employees
WHERE salary > 50000 -- loại nhân viên lương thấp trước
GROUP BY dept
HAVING COUNT(*) > 3; -- giữ phòng có hơn 3 người lương caoSai lầm hay gặp: viết HAVING dept = 'Engineering' thay vì WHERE.
- Nó vẫn chạy nhưng phải quét + gom toàn bảng rồi mới lọc, lại không dùng được index trên
dept. - Quy tắc: đẩy mọi điều kiện không cần aggregate vào
WHEREđể aggregate ít dòng hơn.
Both filter, but at different stages — the key is execution order:
- WHERE runs before
GROUP BY: filters individual rows. Cannot use aggregates (WHERE COUNT(*) > 5is a syntax error). - HAVING runs after
GROUP BY: filters on groups. Can use aggregates (HAVING COUNT(*) > 5).
Example:
sql
SELECT dept, COUNT(*) FROM employees
WHERE salary > 50000 -- drop low-salary employees first
GROUP BY dept
HAVING COUNT(*) > 3; -- keep depts with more than 3 high earnersCommon mistake: writing HAVING dept = 'Engineering' instead of WHERE.
- It works but scans + groups the whole table before filtering, and can't use an index on
dept. - Rule: push every non-aggregate condition into
WHEREso fewer rows get aggregated.