Giới thiệu Mệnh đề HAVING
trong MySQL
Mệnh đề HAVING
trong MySQL thường được sử dụng để lọc các kết quả sau khi đã thực hiện các phép tính nhóm (GROUP BY
). Điểm khác biệt chính giữa HAVING
và WHERE
là HAVING
được áp dụng sau khi các bản ghi đã được nhóm lại, trong khi WHERE
được áp dụng trước khi quá trình nhóm diễn ra.
Cấu trúc cơ bản của mệnh đề HAVING
SELECT column1, aggregate_function(column2)
FROM table_name
WHERE condition
GROUP BY column1
HAVING aggregate_condition
Ở đây:
column1
: Là các cột mà bạn muốn hiển thị.
aggregate_function
: Là các hàm tổng hợp (như COUNT()
, SUM()
, AVG()
, v.v.) để thực hiện tính toán trên các nhóm.
condition
: Là các điều kiện lọc sử dụng với WHERE
.
aggregate_condition
: Là điều kiện lọc trên kết quả của các hàm tổng hợp sử dụng với HAVING
.
Sự khác biệt giữa HAVING
và WHERE
WHERE
: Được sử dụng để lọc dữ liệu trước khi dữ liệu được nhóm (GROUP BY
).
HAVING
: Được sử dụng để lọc các nhóm sau khi áp dụng GROUP BY
.
Các trường hợp sử dụng cụ thể
1. Lọc dữ liệu sau khi sử dụng hàm tổng hợp
Giả sử bạn có một bảng orders
chứa các thông tin về đơn hàng, và bạn muốn liệt kê những sản phẩm nào có tổng số lượng bán ra (SUM(quantity)
) lớn hơn 50.
Ví dụ:
SELECT product_id, SUM(quantity) AS total_quantity
FROM orders
GROUP BY product_id
HAVING total_quantity > 50;
Giải thích:
SUM(quantity)
: Tính tổng số lượng cho mỗi product_id
.
HAVING total_quantity > 50
: Chỉ hiển thị các sản phẩm có tổng số lượng bán ra lớn hơn 50.
2. Sử dụng nhiều điều kiện trong HAVING
Bạn cũng có thể sử dụng nhiều điều kiện trong mệnh đề HAVING
, tương tự như cách bạn sử dụng với WHERE
. Điều này cho phép bạn thực hiện các phép so sánh phức tạp hơn.
Ví dụ:
Giả sử bạn muốn lấy danh sách những sản phẩm có tổng số lượng bán ra lớn hơn 50 và tổng giá trị bán hàng (SUM(price * quantity)
) lớn hơn 10,000.
SELECT product_id, SUM(quantity) AS total_quantity, SUM(price * quantity) AS total_sales
FROM orders
GROUP BY product_id
HAVING total_quantity > 50 AND total_sales > 10000;
Giải thích:
HAVING total_quantity > 50 AND total_sales > 10000
: Điều kiện này chỉ trả về các sản phẩm có tổng số lượng bán ra lớn hơn 50 và tổng doanh thu lớn hơn 10,000.
3. Sử dụng HAVING
với hàm COUNT()
Một tình huống phổ biến khác là bạn muốn đếm số lượng bản ghi và lọc kết quả dựa trên số lượng bản ghi đó.
Ví dụ:
Giả sử bạn có bảng employees
và muốn biết những phòng ban nào có hơn 5 nhân viên.
SELECT department_id, COUNT(employee_id) AS num_employees
FROM employees
GROUP BY department_id
HAVING num_employees > 5;
Giải thích:
COUNT(employee_id)
: Đếm số nhân viên trong mỗi phòng ban.
HAVING num_employees > 5
: Chỉ hiển thị những phòng ban có hơn 5 nhân viên.
4. Kết hợp HAVING
với ORDER BY
Bạn có thể kết hợp HAVING
với ORDER BY
để sắp xếp kết quả sau khi áp dụng điều kiện lọc của HAVING
.
Ví dụ:
Sắp xếp kết quả của ví dụ trên theo số lượng nhân viên giảm dần:
SELECT department_id, COUNT(employee_id) AS num_employees
FROM employees
GROUP BY department_id
HAVING num_employees > 5
ORDER BY num_employees DESC;
Giải thích:
ORDER BY num_employees DESC
: Sắp xếp danh sách theo số lượng nhân viên giảm dần.
5. Sử dụng với các phép so sánh phức tạp
Ngoài các phép so sánh đơn giản, bạn có thể sử dụng các toán tử so sánh như =
, >
, <
, >=
, <=
, <>
hoặc các toán tử logic như AND
, OR
, NOT
trong HAVING
.
Ví dụ:
Giả sử bạn muốn liệt kê các phòng ban có tổng lương nhân viên (SUM(salary)
) lớn hơn 500,000 nhưng số lượng nhân viên không vượt quá 100.
SELECT department_id, SUM(salary) AS total_salary, COUNT(employee_id) AS num_employees
FROM employees
GROUP BY department_id
HAVING total_salary > 500000 AND num_employees <= 100;
Giải thích:
HAVING total_salary > 500000 AND num_employees <= 100
: Điều kiện lọc các phòng ban có tổng lương lớn hơn 500,000 nhưng số lượng nhân viên không quá 100.
6. Sử dụng HAVING
với alias
Trong nhiều trường hợp, bạn có thể sử dụng các alias (bí danh) cho các hàm tổng hợp và sử dụng chúng trong mệnh đề HAVING
.
Ví dụ:
SELECT product_id, COUNT(*) AS total_orders
FROM orders
GROUP BY product_id
HAVING total_orders > 10;
Giải thích:
COUNT(*) AS total_orders
: Đếm số đơn hàng cho mỗi sản phẩm và đặt alias là total_orders
.
HAVING total_orders > 10
: Chỉ trả về các sản phẩm có hơn 10 đơn hàng.
7. Kết hợp HAVING
với các toán tử LIKE
và IN
Bạn có thể sử dụng các toán tử như LIKE
và IN
trong HAVING
để lọc theo các mẫu cụ thể.
Ví dụ:
Giả sử bạn có một bảng employees
và muốn tìm các phòng ban có tên chứa chữ “Sales” và có tổng lương lớn hơn 500,000.
SELECT department_id, SUM(salary) AS total_salary
FROM employees
GROUP BY department_id
HAVING department_id IN (SELECT id FROM departments WHERE name LIKE '%Sales%') AND total_salary > 500000;
Giải thích:
HAVING department_id IN (...)
: Lọc các phòng ban có tên chứa chữ “Sales”.
total_salary > 500000
: Chỉ hiển thị những phòng ban có tổng lương lớn hơn 500,000.
Lưu ý
- Mệnh đề
HAVING
chỉ hoạt động sau khi đã thực hiện việc nhóm dữ liệu với GROUP BY
.
HAVING
thường được sử dụng với các hàm tổng hợp (COUNT()
, SUM()
, AVG()
, v.v.), trong khi WHERE
không thể sử dụng với các hàm này.
Tổng kết
Mệnh đề HAVING
là một công cụ mạnh mẽ trong MySQL để lọc kết quả sau khi nhóm dữ liệu, đặc biệt là khi làm việc với các hàm tổng hợp. Nó cho phép bạn thực hiện các phép tính phức tạp và lọc kết quả dựa trên các giá trị được tổng hợp, giúp tăng hiệu quả và tính linh hoạt trong việc phân tích dữ liệu.
Ví dụ nâng cao về HAVING
1. Lọc kết quả theo nhiều điều kiện với hàm tổng hợp
Giả sử bạn có bảng sales
với các cột region
, product_id
, quantity
, và total_price
. Bạn muốn biết các khu vực (region
) có tổng doanh thu (SUM(total_price)
) lớn hơn 100,000 và có số lượng sản phẩm bán ra (SUM(quantity)
) lớn hơn 500.
Câu truy vấn:
SELECT region, SUM(quantity) AS total_quantity, SUM(total_price) AS total_sales
FROM sales
GROUP BY region
HAVING total_sales > 100000 AND total_quantity > 500;
Giải thích:
SUM(total_price)
tính tổng doanh thu cho mỗi khu vực.
SUM(quantity)
tính tổng số lượng sản phẩm bán ra cho mỗi khu vực.
HAVING total_sales > 100000 AND total_quantity > 500
lọc những khu vực có doanh thu lớn hơn 100,000 và số lượng sản phẩm bán ra lớn hơn 500.
2. Sử dụng mệnh đề HAVING
với JOIN
và hàm tổng hợp
Giả sử bạn có hai bảng: customers
và orders
. Bảng customers
có thông tin khách hàng, và bảng orders
có thông tin đơn hàng. Bạn muốn tìm những khách hàng có tổng giá trị đơn hàng lớn hơn 5,000 nhưng chỉ tính các đơn hàng trong năm 2023.
Cấu trúc bảng:
customers(customer_id, customer_name)
orders(order_id, customer_id, order_date, total_price)
Câu truy vấn:
SELECT c.customer_id, c.customer_name, SUM(o.total_price) AS total_spent
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE YEAR(o.order_date) = 2023
GROUP BY c.customer_id
HAVING total_spent > 5000;
Giải thích:
JOIN
liên kết bảng customers
với orders
dựa trên customer_id
.
WHERE YEAR(o.order_date) = 2023
chỉ lấy các đơn hàng trong năm 2023.
SUM(o.total_price)
tính tổng giá trị đơn hàng cho mỗi khách hàng.
HAVING total_spent > 5000
lọc ra các khách hàng có tổng chi tiêu lớn hơn 5,000.
3. Sử dụng HAVING
với hàm lồng
Giả sử bạn có một bảng employees
chứa thông tin về nhân viên và tiền lương của họ, và bạn muốn tìm những phòng ban có mức lương trung bình lớn hơn mức lương trung bình của toàn bộ công ty.
Cấu trúc bảng:
employees(employee_id, department_id, salary)
Câu truy vấn:
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING avg_salary > (SELECT AVG(salary) FROM employees);
Giải thích:
AVG(salary)
tính mức lương trung bình cho mỗi phòng ban.
SELECT AVG(salary) FROM employees
là một truy vấn con để tính mức lương trung bình của toàn công ty.
HAVING avg_salary > (SELECT AVG(salary) FROM employees)
chỉ trả về các phòng ban có mức lương trung bình cao hơn mức trung bình của toàn công ty.
4. Sử dụng mệnh đề HAVING
với toán tử IN
và SUM()
Giả sử bạn có bảng orders
và bảng products
. Bạn muốn biết những sản phẩm thuộc danh mục “Electronics” có tổng số lượng bán ra lớn hơn 1,000.
Cấu trúc bảng:
orders(order_id, product_id, quantity)
products(product_id, category)
Câu truy vấn:
SELECT p.product_id, SUM(o.quantity) AS total_quantity
FROM orders o
JOIN products p ON o.product_id = p.product_id
WHERE p.category = 'Electronics'
GROUP BY p.product_id
HAVING total_quantity > 1000;
Giải thích:
JOIN
giữa bảng orders
và products
để lấy các sản phẩm thuộc danh mục “Electronics”.
SUM(o.quantity)
tính tổng số lượng sản phẩm đã bán.
HAVING total_quantity > 1000
lọc các sản phẩm có tổng số lượng bán ra lớn hơn 1,000.
5. Sử dụng HAVING
để tìm tỷ lệ phần trăm
Giả sử bạn có bảng student_scores
lưu điểm của sinh viên. Bạn muốn tìm những sinh viên có tỷ lệ điểm số đạt được (score
) so với tổng điểm (total_possible_score
) lớn hơn 80%.
Cấu trúc bảng:
student_scores(student_id, score, total_possible_score)
Câu truy vấn:
SELECT student_id, SUM(score) AS total_score, SUM(total_possible_score) AS total_possible
FROM student_scores
GROUP BY student_id
HAVING (total_score / total_possible) * 100 > 80;
Giải thích:
SUM(score)
tính tổng điểm mà mỗi sinh viên đã đạt được.
SUM(total_possible_score)
tính tổng điểm tối đa mà sinh viên có thể đạt được.
HAVING (total_score / total_possible) * 100 > 80
lọc những sinh viên có tỷ lệ phần trăm đạt trên 80%.
6. Sử dụng HAVING
với COUNT()
và AVG()
Giả sử bạn có bảng reviews
lưu các đánh giá của khách hàng về sản phẩm. Bạn muốn biết những sản phẩm có hơn 10 đánh giá và điểm đánh giá trung bình cao hơn 4.
Cấu trúc bảng:
reviews(review_id, product_id, rating)
Câu truy vấn:
SELECT product_id, COUNT(*) AS total_reviews, AVG(rating) AS avg_rating
FROM reviews
GROUP BY product_id
HAVING total_reviews > 10 AND avg_rating > 4;
Giải thích:
COUNT(*)
đếm số đánh giá cho mỗi sản phẩm.
AVG(rating)
tính điểm đánh giá trung bình cho mỗi sản phẩm.
HAVING total_reviews > 10 AND avg_rating > 4
lọc những sản phẩm có hơn 10 đánh giá và điểm trung bình lớn hơn 4.
Tổng kết:
- Mệnh đề
HAVING
trong MySQL rất mạnh mẽ khi làm việc với các hàm tổng hợp.
- Nó thường được sử dụng để lọc các kết quả sau khi nhóm (
GROUP BY
), đặc biệt khi bạn cần so sánh các giá trị tổng hợp.
- Việc kết hợp
HAVING
với các hàm tổng hợp, JOIN
, hoặc các toán tử logic như AND
, OR
, IN
mang lại sự linh hoạt cao trong việc xử lý dữ liệu phức tạp.
Những ví dụ này cho thấy các tình huống nâng cao mà bạn có thể sử dụng mệnh đề HAVING
để xử lý và phân tích dữ liệu trong MySQL.