SELECT cơ bản và thứ tự thực thi
// File: select.sql
-- Thứ tự LOGIC (khác thứ tự viết!):
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
SELECT category, count(*) AS n
FROM courses
WHERE price > 100000
GROUP BY category
HAVING count(*) >= 3
ORDER BY n DESC
LIMIT 5;
Một trong những nhầm lẫn lớn nhất: WHERE lọc trước khi gộp nhóm, còn HAVING lọc sau khi đã GROUP BY. Đặt điều kiện aggregate vào WHERE sẽ báo lỗi.
JOIN: nối hai bảng lại
| Kiểu JOIN | Kết quả |
|---|---|
| INNER JOIN | Chỉ dòng khớp ở cả hai bảng |
| LEFT JOIN | Tất cả dòng bảng trái, không khớp thì NULL |
| RIGHT JOIN | Đối xứng với LEFT (hiếm dùng) |
| FULL OUTER JOIN | Tất cả dòng cả hai bảng |
// File: join.sql
-- Mỗi khoá học kèm số học viên (kể cả khoá chưa ai đăng ký)
SELECT c.title, count(e.user_id) AS students
FROM courses c
LEFT JOIN enrollments e ON e.course_id = c.id
GROUP BY c.title
ORDER BY students DESC;
-- Chỉ khoá có người học
SELECT c.title
FROM courses c
JOIN enrollments e ON e.course_id = c.id;
Đọc câu query ngược từ SELECT: lấy từ đâu (FROM), ghép với ai (JOIN), lọc ra sao (WHERE/GROUP/HAVING), hiển thị gì. Cách này giúp “bắt mạch” câu SQL của người khác nhanh hơn nhiều.
Aggregate: đếm, cộng, trung bình
// File: aggregate.sql
SELECT
count(*) AS total,
count(DISTINCT student_id) AS unique_students,
round(avg(price), 0) AS avg_price,
sum(amount) AS revenue,
min(created_at) AS first_order
FROM orders;
-- count(*) đếm cả dòng NULL,
-- count(cột) chỉ đếm dòng KHÔNG NULL
Subquery và phòng tránh N+1
Subquery là câu SELECT nằm trong câu khác. Chúng rất mạnh nhưng dễ thành N+1 nếu bạn gọi trong vòng lặp ở code. Quy tắc: nếu lặp rồi query từng dòng, hãy gom lại bằng JOIN hoặc IN.
❓ Bạn muốn đếm số khoá học có giá trên mức trung bình. Bước nào bắt buộc phải dùng?
- Thuộc thứ tự thực thi của SELECT
- Dùng đúng INNER vs LEFT JOIN
- Phân biệt WHERE và HAVING
- Viết được câu có GROUP BY + count