CodeGym /Các khóa học /SQL SELF /So sánh WHERE và HAVING: phân tích thứ tự thực thi và ví ...

So sánh WHERE và HAVING: phân tích thứ tự thực thi và ví dụ

SQL SELF
Mức độ , Bài học
Có sẵn

Hãy cùng mình đi lại một lần nữa về thứ tự thực thi các thao tác trong SQL, cũng như cái gì WHERE và HAVING có thể hoặc không thể làm được. Đây là điểm quan trọng, sau này sẽ có nhiều chi tiết nhỏ trong việc viết truy vấn SQL dựa trên nó. Bạn cần hiểu thật kỹ phần này nha.

Vậy WHERE khác HAVING ở chỗ nào, khi nào dùng cái này, khi nào dùng cái kia, và chúng liên quan với nhau ra sao? Hiểu rõ cái này sẽ giúp bạn không bị rối khi viết truy vấn và lọc dữ liệu hiệu quả hơn. Tổng kết lại kiến thức về WHEREHAVING nhé.

WHERE là gì?

WHERE — là điều kiện dùng để lọc các dòng trước khi nhóm hoặc dùng các hàm tổng hợp. Tức là, đầu tiên sẽ chọn ra các dòng thỏa mãn điều kiện từ bảng, rồi mới thực hiện nhóm trên dữ liệu còn lại.

👉 Hình dung như bạn đi chợ chọn trái cây. WHERE — là bộ lọc giúp bạn loại bỏ táo dập, hỏng trước khi bạn bắt đầu phân loại theo kích thước hay màu sắc.

Ví dụ:

SELECT *
FROM students
WHERE age > 18;

Truy vấn này sẽ chọn tất cả sinh viên trên 18 tuổi trước khi thực hiện các thao tác khác.

HAVING là gì?

HAVING — là bộ lọc được áp dụng sau khi đã nhóm dữ liệu (GROUP BY). Nó cho phép đặt điều kiện lên các nhóm, ví dụ chỉ giữ lại những nhóm mà điểm trung bình của sinh viên lớn hơn 80.

👉 Quay lại ví dụ với táo. HAVING — là bộ lọc dùng sau khi bạn đã phân táo vào từng giỏ (nhóm). Giờ bạn chỉ quan tâm đến những giỏ (nhóm) có hơn mười quả táo thôi chẳng hạn.

Ví dụ:

SELECT giỏ, COUNT(*)
FROM táo
GROUP BY giỏ
HAVING COUNT(*) > 10;

Truy vấn này sẽ chỉ chọn những giỏ có số lượng táo lớn hơn 10.

Khác biệt chính:

Đặc điểm WHERE HAVING
Áp dụng Lọc dòng trước khi nhóm Lọc nhóm sau khi nhóm
Làm việc với tổng hợp Không dùng được hàm tổng hợp Dùng được hàm tổng hợp
Mục đích Loại bỏ dòng dư thừa trước khi nhóm Loại bỏ nhóm không thỏa điều kiện

Thứ tự thực thi WHERE, GROUP BYHAVING

Để hiểu rõ hơn cách WHEREHAVING hoạt động, cùng xem thứ tự thực thi truy vấn SQL:

  1. Đầu tiên là FROM, chọn dòng từ bảng.
  2. Sau đó áp dụng WHERE, chỉ giữ lại dòng thỏa điều kiện.
  3. Tiếp theo là nhóm dữ liệu bằng GROUP BY. Ta có bảng mới với các nhóm.
  4. Áp dụng HAVING, lọc các nhóm thỏa điều kiện.
  5. Cuối cùng là chọn kết quả với SELECT.

Minh họa như sau:

1. FROM → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT

Ví dụ:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE age > 18
GROUP BY department
HAVING AVG(age) > 20;

Ở đây sẽ diễn ra như sau:

  1. Chọn dòng trong bảng studentsage > 18 (dùng WHERE).
  2. Các dòng còn lại được nhóm theo department.
  3. Tính tuổi trung bình cho từng nhóm sinh viên.
  4. Nhóm nào có tuổi trung bình nhỏ hơn hoặc bằng 20 sẽ bị loại (HAVING).
  5. Xuất kết quả.

Ví dụ kết hợp sử dụng

Ví dụ 1: Lọc trước và sau khi nhóm

Yêu cầu: tìm các khoa có hơn 5 sinh viên, chỉ tính sinh viên trên 18 tuổi.

Bảng gốc students

id name department age gpa
1 Alex Lin ComputerSci 20 3.8
2 Maria Chi Math 22 3.5
3 Anna Song ComputerSci 19 4.0
4 Otto Art Math 17 3.9
5 Liam Park Physics 21 3.7
6 Jane Doe ComputerSci 23 3.6
7 Tom Brown Math 25 3.4
8 Sara White Math 19 3.8
9 John Smith ComputerSci 20 3.7
10 Emily Green Physics 18 3.9
11 Mark Blue ComputerSci 21 3.5
12 Zoe Black Math 22 3.6
13 Max Gray ComputerSci 20 3.9
14 Eva Gold Math 23 3.7
15 Nick Silver Physics 19 3.8

Truy vấn:

SELECT department, COUNT(*) AS student_count
FROM students
WHERE age > 18
GROUP BY department
HAVING COUNT(*) > 5;

Kết quả: -- Kết quả truy vấn

department student_count
ComputerSci 6

Giải thích:

  1. Đầu tiên loại bỏ dòng mà age <= 18 (điều kiện WHERE).
  2. Nhóm dữ liệu theo khoa (GROUP BY department).
  3. Tính số sinh viên trong từng nhóm.
  4. Loại bỏ nhóm có số sinh viên nhỏ hơn hoặc bằng 5 (HAVING COUNT(*) > 5).

Ví dụ 2: Lỗi khi dùng WHERE thay vì HAVING

Yêu cầu: Tìm các khoa có tuổi trung bình lớn hơn 22.

Truy vấn sai:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE AVG(age) > 22
GROUP BY department;

Lỗi: SQL không cho dùng hàm tổng hợp AVG trong WHERE, vì ở bước này chưa tính xong aggregate.

Truy vấn đúng:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 22;

Ở đây điều kiện AVG(age) > 22 được áp dụng sau khi nhóm.

Mẹo thực tế

Nếu bạn cần lọc dòng, dùng WHERE. Ví dụ: Tìm tất cả nhân viên có lương trên 5000.

SELECT *
FROM employees
WHERE salary > 5000;

Nếu bạn cần lọc nhóm, dùng HAVING. Ví dụ: Tìm các phòng ban có tổng lương trên 100 000.

SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING SUM(salary) > 100000;

Kết hợp WHEREHAVING cho điều kiện phức tạp.

Ví dụ: Tìm các quốc gia có dân số trên 10 triệu, chỉ tính các thành phố có dân số trên 1 triệu.

SELECT country, SUM(population) AS total_population
FROM cities
WHERE population > 1000000
GROUP BY country
HAVING SUM(population) > 10000000;

Lỗi thường gặp và cách xử lý

Một trong những lỗi phổ biến nhất là nhầm lẫn giữa WHEREHAVING. Ví dụ, thử dùng hàm tổng hợp trong WHERE:

SELECT department, COUNT(*)
FROM students
WHERE COUNT(*) > 10
GROUP BY department;

Truy vấn này sẽ báo lỗi vì không thể tính aggregate ở bước WHERE. Cách đúng là dùng HAVING:

SELECT department, COUNT(*)
FROM students
GROUP BY department
HAVING COUNT(*) > 10;

Một lỗi nữa là chọn sai điều kiện cho WHERE. Ví dụ:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE avg_age > 20
GROUP BY department;

Ở đây điều kiện avg_age > 20 là sai, vì avg_age chưa được tính ở bước này. Giải pháp là chuyển điều kiện này sang HAVING:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 20;

Hy vọng giờ bạn đã hiểu rõ sự khác biệt giữa WHEREHAVING, cách dùng đúng và tránh lỗi thường gặp. Kiến thức này sẽ rất hữu ích khi bạn viết báo cáo phức tạp, lọc dữ liệu để phân tích và tối ưu truy vấn. Nói chung là cho phần lớn các truy vấn SQL thực tế mà bạn sẽ viết :)

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION