PHP và MySQL Bài 20: Truy vấn nâng cao - Lọc, Sắp xếp và Phân nhóm dữ liệu với WHERE, ORDER BY, LIMIT, GROUP BY
Để trích xuất chính xác thông tin mình cần giữa một "biển" dữ liệu, bạn cần biết cách đặt ra các điều kiện truy vấn. Dưới đây là 5 mệnh đề quan trọng nhất luôn đi kèm với câu lệnh SELECT.
1. Mệnh đề WHERE - Bộ lọc dữ liệu chính xác
Mệnh đề WHERE cho phép bạn chỉ định các điều kiện. MySQL sẽ kiểm tra từng dòng, dòng nào thỏa mãn điều kiện (trả về TRUE) thì mới được đưa vào kết quả trả về.
Các toán tử thường dùng trong WHERE:
- So sánh:
=,<,>,<=,>=,!=(Khác) - Logic:
AND(Và),OR(Hoặc),NOT(Phủ định) - Khoảng giá trị:
BETWEEN ... AND ... - Nằm trong danh sách:
IN (giá_trị_1, giá_trị_2, ...) - Tìm kiếm chuỗi (Khớp mẫu):
LIKE(sử dụng dấu%đại diện cho một chuỗi bất kỳ).
Ví dụ thực tế:
-- Tìm tất cả nhân viên đang hoạt động (status = 1) VÀ có tuổi trên 25
SELECT * FROM users WHERE status = 1 AND age > 25;
-- Tìm những giao dịch bị lỗi (status = 0) phát sinh trong tháng 7/2026
SELECT * FROM transactions WHERE status = 0 AND created_at BETWEEN '2026-07-01' AND '2026-07-31';
-- Lấy thông tin các trạm kiểm soát thuộc danh sách được chỉ định
SELECT * FROM stations WHERE station_code IN ('ST01', 'ST02', 'ST05');
-- Tìm kiếm tất cả khách hàng sử dụng email của Google (kết thúc bằng @gmail.com)
SELECT * FROM customers WHERE email LIKE '%@gmail.com';
2. Mệnh đề ORDER BY - Sắp xếp kết quả
Khi lấy dữ liệu ra, thứ tự mặc định thường là thứ tự chúng được thêm vào bảng. Để sắp xếp danh sách theo ý muốn (ví dụ: mới nhất xếp trước, giá rẻ nhất xếp trước), ta dùng ORDER BY.
ASC(Ascending): Sắp xếp tăng dần (A-Z, 0-9). Đây là mặc định nếu bạn không ghi gì thêm.DESC(Descending): Sắp xếp giảm dần (Z-A, 9-0).
Ví dụ:
-- Lấy danh sách sản phẩm, sắp xếp theo giá từ cao xuống thấp
SELECT product_name, price FROM products ORDER BY price DESC;
-- Lấy danh sách bài viết mới nhất (thời gian tạo giảm dần)
SELECT title, created_at FROM articles ORDER BY created_at DESC;
3. Mệnh đề LIMIT - Giới hạn số lượng & Phân trang
Nếu kết quả truy vấn trả về 10,000 bản ghi, việc hiển thị tất cả lên màn hình sẽ làm treo trình duyệt. LIMIT giúp bạn "cắt" lấy một số lượng dòng nhất định. Nó là chìa khóa để làm tính năng Phân trang (Pagination).
Cú pháp: LIMIT offset, so_luong
offset: Bỏ qua bao nhiêu dòng đầu tiên (Bắt đầu từ 0).so_luong: Số lượng dòng muốn lấy.
Ví dụ:
-- Chỉ lấy 5 người dùng mới đăng ký nhất (Kết hợp ORDER BY và LIMIT)
SELECT username FROM users ORDER BY created_at DESC LIMIT 5;
-- Ứng dụng phân trang: Mỗi trang hiện 10 sản phẩm
-- Trang 1 (Bỏ qua 0 dòng, lấy 10 dòng):
SELECT * FROM products LIMIT 0, 10;
-- Trang 2 (Bỏ qua 10 dòng đầu, lấy 10 dòng tiếp theo):
SELECT * FROM products LIMIT 10, 10;
4. Mệnh đề GROUP BY - Gom nhóm và Thống kê
Khi bạn muốn thống kê dữ liệu tổng quan, thay vì lấy ra từng dòng riêng lẻ, bạn gom những dòng có chung đặc điểm thành một nhóm. GROUP BY bắt buộc phải đi kèm với các hàm tổng hợp (Aggregate Functions) như:
COUNT(): Đếm số lượng.SUM(): Tính tổng.AVG(): Tính trung bình.MAX()/MIN(): Tìm giá trị lớn nhất / nhỏ nhất.
Ví dụ: Bạn có một bảng transactions ghi lại hàng ngàn giao dịch vé.
-- Đếm xem mỗi trạm (station_id) có bao nhiêu giao dịch trong ngày
SELECT station_id, COUNT(id) AS total_transactions FROM transactions GROUP BY station_id;
-- Tính tổng doanh thu của từng loại vé
SELECT ticket_type, SUM(price) AS total_revenue FROM transactions GROUP BY ticket_type;
(Từ khóa AS dùng để đặt bí danh cho cột kết quả, giúp tên cột hiển thị đẹp và dễ đọc hơn khi gọi bằng PHP).
5. Mệnh đề HAVING - Lọc kết quả sau khi đã gom nhóm
Đây là kiến thức thường xuyên xuất hiện trong các bài phỏng vấn Backend.
Nhiều người thắc mắc: Tại sao không dùng WHERE để lọc luôn dữ liệu thống kê?
Câu trả lời là: WHERE lọc dữ liệu TRƯỚC KHI gom nhóm, còn HAVING lọc dữ liệu SAU KHI đã gom nhóm.
Ví dụ: Bạn muốn đếm số lượng giao dịch của từng trạm, nhưng chỉ hiển thị những trạm nào có tổng doanh thu lớn hơn 10 triệu đồng. Bạn không thể dùng WHERE SUM(price) > 10000000 vì lúc máy chủ xử lý WHERE, nó chưa hề tính tổng.
Cách làm đúng:
SELECT station_id, SUM(price) AS total_revenue
FROM transactions
GROUP BY station_id
HAVING total_revenue > 10000000;
Tổng kết Bài 20
Sự kết hợp giữa WHERE (tìm kiếm), ORDER BY (sắp xếp), LIMIT (phân trang) và GROUP BY (thống kê) tạo nên một thứ vũ khí hoàn hảo giúp Backend Developer làm chủ mọi luồng dữ liệu, phục vụ cho việc xây dựng các bộ lọc sản phẩm phức tạp hay các trang Dashboard báo cáo.
Đến đây, chúng ta mới chỉ thao tác trên một bảng duy nhất. Trong thực tế, dữ liệu luôn được chia nhỏ ra nhiều bảng để tránh trùng lặp. Ở bài tiếp theo, chúng ta sẽ học cách "lắp ghép" chúng lại.
Đón chờ Bài 21: Khái niệm Khóa chính (Primary Key), Khóa ngoại (Foreign Key) và các mối quan hệ (1-1, 1-N, N-N).
All rights reserved