Giao diện
SQL Cheatsheet - Tất cả trong một 📖
Chào anh em! Đây là tài liệu tổng hợp tất cả các câu lệnh SQL quan trọng mà anh em cần biết. Mình đã chia thành các phần rõ ràng để anh em dễ tra cứu.
📌 Mục lục nhanh
| Phần | Nội dung |
|---|---|
| SELECT | Truy vấn dữ liệu cơ bản |
| WHERE | Điều kiện lọc |
| JOIN | Kết hợp bảng |
| GROUP BY | Nhóm dữ liệu |
| HAVING | Lọc sau khi nhóm |
| ORDER BY | Sắp xếp kết quả |
| INSERT/UPDATE/DELETE | Thao tác dữ liệu |
SELECT - Truy vấn dữ liệu
Cú pháp cơ bản
sql
-- Lấy tất cả các cột
SELECT * FROM users;
-- Lấy các cột cụ thể (KHUYẾN KHÍCH!)
SELECT id, name, email FROM users;
-- Đặt alias cho cột
SELECT
first_name AS "Họ",
last_name AS "Tên",
salary * 12 AS "Lương năm"
FROM employees;
-- Loại bỏ giá trị trùng
SELECT DISTINCT department FROM employees;💡 Mẹo của HPN
LUÔN chỉ định cột cụ thể thay vì dùng SELECT *. Điều này giúp:
- Query nhanh hơn (ít data truyền tải)
- Code rõ ràng hơn
- Tránh lỗi khi schema thay đổi
WHERE - Điều kiện lọc
Các toán tử so sánh
| Toán tử | Ý nghĩa | Ví dụ |
|---|---|---|
= | Bằng | WHERE status = 'active' |
<> hoặc != | Khác | WHERE status <> 'deleted' |
>, < | Lớn/Nhỏ hơn | WHERE age > 18 |
>=, <= | Lớn/Nhỏ hơn hoặc bằng | WHERE price <= 100 |
BETWEEN | Trong khoảng | WHERE age BETWEEN 18 AND 65 |
IN | Trong danh sách | WHERE status IN ('active', 'pending') |
LIKE | Pattern matching | WHERE name LIKE 'Nguyễn%' |
IS NULL | Kiểm tra NULL | WHERE phone IS NULL |
Pattern Matching với LIKE
sql
-- Bắt đầu bằng "Nguyễn"
SELECT * FROM users WHERE name LIKE 'Nguyễn%';
-- Kết thúc bằng "@gmail.com"
SELECT * FROM users WHERE email LIKE '%@gmail.com';
-- Chứa "dev" ở bất kỳ đâu
SELECT * FROM users WHERE bio LIKE '%dev%';
-- Đúng 5 ký tự (mỗi _ là 1 ký tự)
SELECT * FROM products WHERE code LIKE '_____';Kết hợp điều kiện
sql
-- AND: Cả 2 điều kiện đều đúng
SELECT * FROM products
WHERE category = 'Electronics'
AND price < 1000;
-- OR: Ít nhất 1 điều kiện đúng
SELECT * FROM products
WHERE category = 'Books'
OR category = 'Music';
-- NOT: Phủ định điều kiện
SELECT * FROM users
WHERE NOT status = 'banned';
-- Kết hợp phức tạp (dùng ngoặc!)
SELECT * FROM orders
WHERE status = 'completed'
AND (total > 1000000 OR vip_customer = true);⚠️ Lỗi thường gặp
Khi kết hợp AND và OR, LUÔN sử dụng ngoặc đơn để rõ ràng thứ tự ưu tiên!
sql
-- ❌ SAI: Logic có thể sai
WHERE a = 1 OR b = 2 AND c = 3
-- ✅ ĐÚNG: Rõ ràng logic
WHERE a = 1 OR (b = 2 AND c = 3)JOIN - Kết hợp bảng
Minh họa các loại JOIN
Bảng A (users) Bảng B (orders)
+----+--------+ +----+---------+--------+
| id | name | | id | user_id | total |
+----+--------+ +----+---------+--------+
| 1 | Hùng | | 1 | 1 | 500k |
| 2 | Lan | | 2 | 1 | 300k |
| 3 | Minh | | 3 | 4 | 200k | ← user_id=4 không tồn tại!
+----+--------+ +----+---------+--------+INNER JOIN (Giao)
Chỉ lấy các bản ghi có khớp ở cả 2 bảng.
sql
-- Lấy users VÀ orders của họ
SELECT
u.name AS "Tên khách",
o.id AS "Mã đơn",
o.total AS "Tổng tiền"
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- Kết quả: Chỉ có Hùng (có đơn hàng)
-- Minh không xuất hiện (không có đơn)
-- Order id=3 không xuất hiện (user không tồn tại)LEFT JOIN (Bảng trái là chính)
Lấy TẤT CẢ từ bảng trái, khớp gì lấy từ bảng phải.
sql
SELECT
u.name AS "Tên khách",
o.id AS "Mã đơn",
COALESCE(o.total, 0) AS "Tổng tiền"
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- Kết quả:
-- Hùng | 1 | 500k
-- Hùng | 2 | 300k
-- Lan | NULL | 0 ← Lan chưa có đơn
-- Minh | NULL | 0 ← Minh chưa có đơnRIGHT JOIN (Bảng phải là chính)
sql
SELECT
u.name AS "Tên khách",
o.id AS "Mã đơn"
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
-- Kết quả:
-- Hùng | 1
-- Hùng | 2
-- NULL | 3 ← Order không có user hợp lệFULL OUTER JOIN (Hợp của 2 bảng)
sql
SELECT
u.name,
o.id
FROM users u
FULL OUTER JOIN orders o ON u.id = o.user_id;
-- Kết quả: Tất cả từ cả 2 bảng, NULL nếu không khớp📊 Tổng hợp các loại JOIN
| JOIN Type | Bảng trái | Bảng phải | Điều kiện |
|---|---|---|---|
| INNER | Chỉ khớp | Chỉ khớp | Phải khớp cả 2 |
| LEFT | Tất cả | Chỉ khớp | Bảng trái là master |
| RIGHT | Chỉ khớp | Tất cả | Bảng phải là master |
| FULL | Tất cả | Tất cả | Lấy hết, NULL nếu không khớp |
GROUP BY - Nhóm dữ liệu
Cú pháp cơ bản
sql
-- Đếm số đơn hàng theo trạng thái
SELECT
status AS "Trạng thái",
COUNT(*) AS "Số lượng"
FROM orders
GROUP BY status;
-- Tổng doanh thu theo tháng
SELECT
DATE_TRUNC('month', created_at) AS "Tháng",
SUM(total) AS "Doanh thu"
FROM orders
WHERE status = 'completed'
GROUP BY DATE_TRUNC('month', created_at)
ORDER BY "Tháng";Các hàm Aggregate phổ biến
| Hàm | Ý nghĩa | Ví dụ |
|---|---|---|
COUNT(*) | Đếm tổng số dòng | COUNT(*) |
COUNT(column) | Đếm giá trị non-NULL | COUNT(email) |
SUM(column) | Tổng | SUM(total) |
AVG(column) | Trung bình | AVG(price) |
MIN(column) | Giá trị nhỏ nhất | MIN(created_at) |
MAX(column) | Giá trị lớn nhất | MAX(salary) |
HAVING - Lọc sau khi nhóm
💡 WHERE vs HAVING
WHERE: Lọc TRƯỚC khi nhóm (lọc từng dòng)HAVING: Lọc SAU khi nhóm (lọc kết quả aggregate)
sql
-- Tìm category có nhiều hơn 10 sản phẩm
SELECT
category,
COUNT(*) AS product_count
FROM products
WHERE is_active = true -- Lọc sản phẩm active TRƯỚC
GROUP BY category
HAVING COUNT(*) > 10; -- Lọc nhóm SAU
-- Tìm user đã mua tổng > 10 triệu
SELECT
user_id,
SUM(total) AS total_spent
FROM orders
WHERE status = 'completed'
GROUP BY user_id
HAVING SUM(total) > 10000000
ORDER BY total_spent DESC;ORDER BY - Sắp xếp
sql
-- Sắp xếp tăng dần (mặc định)
SELECT * FROM products ORDER BY price;
SELECT * FROM products ORDER BY price ASC;
-- Sắp xếp giảm dần
SELECT * FROM products ORDER BY price DESC;
-- Sắp xếp nhiều cột
SELECT * FROM employees
ORDER BY department ASC, salary DESC;
-- Sắp xếp theo vị trí cột (không khuyến khích)
SELECT name, price FROM products ORDER BY 2 DESC;
-- NULL đầu tiên hoặc cuối cùng
SELECT * FROM users ORDER BY phone NULLS LAST;CRUD Operations
INSERT - Thêm dữ liệu
sql
-- Thêm 1 dòng
INSERT INTO users (name, email, created_at)
VALUES ('Nguyễn Văn A', 'a@email.com', NOW());
-- Thêm nhiều dòng
INSERT INTO products (name, price, category) VALUES
('iPhone 15', 25000000, 'Electronics'),
('MacBook Pro', 50000000, 'Electronics'),
('AirPods', 4000000, 'Electronics');
-- Insert từ SELECT
INSERT INTO archived_orders (id, user_id, total)
SELECT id, user_id, total
FROM orders
WHERE created_at < '2023-01-01';UPDATE - Cập nhật dữ liệu
sql
-- Cập nhật 1 trường
UPDATE users SET status = 'inactive' WHERE id = 123;
-- Cập nhật nhiều trường
UPDATE products
SET
price = price * 1.1, -- Tăng 10%
updated_at = NOW()
WHERE category = 'Electronics';🚨 CẢNH BÁO NGHIÊM TRỌNG
KHÔNG BAO GIỜ chạy UPDATE hoặc DELETE mà KHÔNG CÓ WHERE!
sql
-- ❌ RẤT NGUY HIỂM - Sẽ update TẤT CẢ users!
UPDATE users SET status = 'deleted';
-- ✅ An toàn - Chỉ update user cụ thể
UPDATE users SET status = 'deleted' WHERE id = 123;Mẹo an toàn: Luôn chạy SELECT với điều kiện tương tự TRƯỚC khi UPDATE/DELETE:
sql
-- Bước 1: Kiểm tra data sẽ bị ảnh hưởng
SELECT * FROM users WHERE status = 'inactive';
-- Bước 2: Nếu đúng, mới chạy DELETE
DELETE FROM users WHERE status = 'inactive';DELETE - Xóa dữ liệu
sql
-- Xóa có điều kiện
DELETE FROM orders WHERE status = 'cancelled';
-- Xóa dựa trên subquery
DELETE FROM cart_items
WHERE user_id IN (
SELECT id FROM users WHERE status = 'deleted'
);🎁 Bonus: Các hàm hữu ích
Xử lý NULL
sql
-- COALESCE: Thay NULL bằng giá trị mặc định
SELECT COALESCE(phone, 'Chưa có SĐT') FROM users;
-- NULLIF: Trả về NULL nếu 2 giá trị bằng nhau
SELECT NULLIF(discount, 0) FROM products;Xử lý chuỗi
sql
-- Nối chuỗi
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
SELECT first_name || ' ' || last_name AS full_name FROM users; -- PostgreSQL
-- Upper/Lower
SELECT UPPER(email), LOWER(name) FROM users;
-- Cắt khoảng trắng
SELECT TRIM(name) FROM users;
-- Substring
SELECT SUBSTRING(phone, 1, 4) AS prefix FROM users;Xử lý ngày tháng
sql
-- Lấy ngày hiện tại
SELECT CURRENT_DATE, CURRENT_TIMESTAMP, NOW();
-- Extract thành phần
SELECT
EXTRACT(YEAR FROM created_at) AS year,
EXTRACT(MONTH FROM created_at) AS month
FROM orders;
-- Format ngày (PostgreSQL)
SELECT TO_CHAR(created_at, 'DD/MM/YYYY HH24:MI') FROM orders;📚 Tài liệu tham khảo
📖 Happy querying, anh em! 🚀