Chuyển đến nội dung chính
Mô-đun 3 · Bài học 4 trong tổng số 412/57 trong khóa học~8 min
Bài học theo mô-đun (4/4)

Nhóm lọc: CÓ

Khi bạn đã có kết quả cho mỗi nhóm (bài trước), bạn thường muốn chỉ giữ lại các nhóm thỏa mãn một điều kiện: các phòng ban có nhiều hơn hơn 2 người, các dự án có ngân sách trung bình trên 100 nghìn, người dùng có ít nhất 10 đơn hàng. Để làm điều này WHERE không đủ.

Tại sao WHERE là không đủ

WHERE lọc tập hợp các hàng trong bảng, trước. Vì vậy nó không thể nhìn thấy kết quả của COUNT(*) hoặc AVG(...): vào thời điểm WHERE chạy, những kết quả đó các giá trị chưa được tính toán.

SQL
-- ERROR: COUNT(*) doesn't exist yet when WHERE is evaluated
SELECT department_id, COUNT(*) AS count
FROM   employees
WHERE  COUNT(*) > 2     -- ❌ doesn't work
GROUP BY department_id;

Để lọc sau tổng hợp, có một mệnh đề dành riêng: HAVING.

Cú pháp

SQL
SELECT grouping_column, AGGREGATE_FUNCTION(...)
FROM   table
GROUP BY grouping_column
HAVING   condition_on_aggregate;
SQL
-- Departments with more than 2 employees:
SELECT department_id, COUNT(*) AS count
FROM   employees
GROUP BY department_id
HAVING   COUNT(*) > 2;

HAVING là của GROUP BY WHERE là của FROM: cùng một ý tưởng ("bộ lọc"), nhưng được áp dụng sau nhóm, trên tổng thể.

Thứ tự logic của các mệnh đề

Để không bao giờ nhầm lẫn giữa WHERE và HAVING nữa, hãy nhớ thứ tự SQL thực thi chúng một cách tinh thần:

  1. FROM / JOIN — xây dựng bảng bắt đầu bằng cách nối các nguồn.
  2. WHERE — bỏ những hàng bạn không quan tâm.
  3. GROUP BY — tập hợp các hàng còn lại thành nhóm.
  4. HAVING — xóa các nhóm mà bạn không quan tâm.
  5. SELECT — tính toán các cột cuối cùng (bao gồm cả tổng hợp).
  6. ORDER BY / LIMIT — sắp xếp lại và cắt.

Lưu ý quan trọng:

  • trong WHERE bạn chỉ có thể sử dụng cột bảng;
  • trong HAVING bạn có thể sử dụng nhóm cột và tổng hợp.
SQL
-- Classic combo: filter first, group, filter the groups, sort.
SELECT d.name, AVG(e.salary) AS average
FROM   employees   AS e
JOIN   departments AS d ON e.department_id = d.id
WHERE  e.hired_on >= '2018-01-01'   -- filter rows
GROUP BY d.name
HAVING   AVG(e.salary) > 35000      -- filter groups
ORDER BY average DESC;

Hãy thử nó

tập thể dục#sql.m3.l4.e1
Nỗ lực: 0Đang tải…

Đối với mỗi bộ phận, hiển thị tên (departments.name) và số lượng nhân viên, NHƯNG chỉ dành cho những bộ phận có ít nhất 2 nhân viên. Hai cột, một hàng cho mỗi bộ phận đủ điều kiện.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

Điều kiện 'ít nhất 2' trở thành COUNT(*) >= 2 trong HAVING.

Giải pháp khả dụng sau 3 lần thử

Xem lại bài tập

tập thể dục#sql.m3.l4.e2
Nỗ lực: 0Đang tải…

Hiển thị các phòng ban (departments.name) có mức lương trung bình vượt quá 35000. Chỉ xem xét những nhân viên được tuyển dụng từ năm 2018 trở đi. Hai cột: tên và mức trung bình. Sắp xếp theo mức trung bình giảm dần.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

WHERE lọc các hàng (nhân viên được tuyển dụng từ năm 2018), HAVING lọc các nhóm (trung bình > 35000).

Giải pháp khả dụng sau 3 lần thử