IF và CASE WHEN
Bạn sẽ học được
- Chuyển
IFlồng nhau sangCASE WHEN. - Xử lý nhiều nhánh và giá trị mặc định.
- Dùng
CASEtrongSELECT,WHEREvàORDER BY. - Ánh xạ
IFERRORsangCOALESCEvàNULLIF. - Tránh lỗi logic khi điều kiện chồng lấn.
Khái niệm cốt lõi
Excel dùng IF(điều kiện, giá trị đúng, giá trị sai); SQL dùng CASE WHEN ... THEN ... ELSE ... END. CASE là biểu thức, nên dùng được ở bất kỳ chỗ nào cần giá trị: cột kết quả, điều kiện lọc, khóa sắp xếp.
| Excel | SQL |
|---|---|
=IF(A2>1000, "Cao", "Thấp") | CASE WHEN x > 1000 THEN 'Cao' ELSE 'Thấp' END |
=IF(A2>1000, "Cao", IF(A2>500, "TB", "Thấp")) | CASE WHEN x > 1000 THEN 'Cao' WHEN x > 500 THEN 'TB' ELSE 'Thấp' END |
=IFERROR(A2/B2, 0) | COALESCE(a / NULLIF(b, 0), 0) |
=IF(ISBLANK(A2), "Thiếu", A2) | COALESCE(NULLIF(trim(a), ''), 'Thiếu') |
CASE trong SELECT
SELECT o.id,
o.order_date,
oi.quantity * oi.unit_price AS thanh_tien,
CASE
WHEN oi.quantity * oi.unit_price >= 1000000 THEN 'Lớn'
WHEN oi.quantity * oi.unit_price >= 300000 THEN 'Trung bình'
ELSE 'Nhỏ'
END AS nhom_gia_tri
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
WHERE o.status = 'completed';Thứ tự WHEN quyết định kết quả: CASE dừng ở nhánh đầu tiên đúng. Nếu đặt >= 300000 trước >= 1000000, mọi dòng từ 300.000 trở lên đều thành "Trung bình". Đây là lỗi logic phổ biến nhất khi chuyển từ IF lồng nhau.
Quy tắc: sắp điều kiện từ hẹp nhất đến rộng nhất, và luôn có ELSE (nếu không, giá trị không khớp trả NULL).
CASE trong WHERE và ORDER BY
Lọc theo giá trị đã phân nhóm:
SELECT *
FROM (
SELECT o.id,
oi.quantity * oi.unit_price AS thanh_tien
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
) t
WHERE CASE WHEN thanh_tien >= 1000000 THEN 'Lớn' ELSE 'Khác' END = 'Lớn';Thực tế nên lặp điều kiện trực tiếp (WHERE thanh_tien >= 1000000) thay vì bọc CASE — dễ đọc và dùng được index. CASE trong WHERE chỉ hữu ích khi điều kiện phức tạp hoặc cần tái sử dụng logic phân nhóm.
Sắp xếp theo thứ tự nghiệp vụ, không theo alphabet:
SELECT id, status
FROM orders
ORDER BY CASE status
WHEN 'pending' THEN 1
WHEN 'completed' THEN 2
WHEN 'cancelled' THEN 3
ELSE 4
END;Nếu sắp theo chuỗi, cancelled đứng trước completed — sai với mong muốn.
IFERROR: COALESCE và NULLIF
Excel IFERROR bắt mọi lỗi, kể cả lỗi logic. SQL tách thành hai việc:
NULLIF(b, 0)biến mẫu số 0 thànhNULL, tránh chia cho 0.COALESCE(x, 0)thayNULLbằng giá trị mặc định.
SELECT p.name,
COALESCE(SUM(oi.quantity)::numeric / NULLIF(p.stock, 0), 0) AS ty_le_ban_ra
FROM products p
LEFT JOIN order_items oi ON oi.product_id = p.id
GROUP BY p.id, p.name, p.stock;LEFT JOIN giữ sản phẩm chưa bán; COALESCE biến NULL thành 0. Không dùng NULLIF thì stock = 0 gây lỗi chia cho 0.
Khác biệt với IFERROR: SQL không nuốt lỗi cú pháp hay lỗi kiểu dữ liệu. Đó là điều tốt — lỗi thật phải nổi lên, không bị thay bằng 0 âm thầm.
Kiểm tra giá trị thiếu
SELECT id, name,
CASE WHEN email IS NULL OR trim(email) = '' THEN 'Thiếu email' ELSE 'Có email' END AS trang_thai_email
FROM customers;Với dữ liệu nhập tay, chuỗi rỗng và khoảng trắng phổ biến hơn NULL. Kiểm tra cả hai. Nếu cần đếm nhanh:
SELECT COUNT(*) FILTER (WHERE email IS NULL) AS thieu_null,
COUNT(*) FILTER (WHERE trim(email) = '') AS thieu_rong
FROM customers;CASE lồng và bảng tra cứu
Khi số nhánh tăng, CASE dài dần và khó bảo trì. Lúc đó nên dùng bảng ánh xạ:
-- Thay vì CASE 20 nhánh
SELECT o.id, m.nhan
FROM orders o
JOIN mapping_status m ON m.status = o.status;Với vài nhánh (3–5), CASE gọn hơn. Với hàng chục nhánh hoặc nhánh thay đổi thường xuyên, bảng tra cứu cho phép cập nhật dữ liệu mà không sửa truy vấn.
Thực hành
- Viết
CASEphân nhóm giá trị đơn thành Lớn/Trung bình/Nhỏ. - Đảo thứ tự
WHENvà quan sát kết quả thay đổi. - Dùng
CASEsắp xếp trạng thái theo thứ tự nghiệp vụ. - Tính tỷ lệ bán ra với
NULLIFđể tránh chia cho 0. - Đếm khách thiếu email bằng cả
IS NULLvà chuỗi rỗng.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
| Mọi dòng vào nhánh đầu | WHEN rộng đặt trước | Sắp từ hẹp đến rộng |
Kết quả NULL bất ngờ | Thiếu ELSE | Thêm nhánh mặc định |
| Chia cho 0 | Mẫu số bằng 0 | NULLIF(mau_so, 0) |
| Lỗi bị che mất | Bắt quá rộng như IFERROR | Chỉ xử lý NULL, để lỗi thật nổi lên |
| Chuỗi rỗng không bị bắt | Chỉ kiểm tra IS NULL | Thêm trim(cot) = '' |
CASE dài khó sửa | Quá nhiều nhánh | Chuyển sang bảng ánh xạ |
| Sắp xếp sai thứ tự | Sắp theo chuỗi | Dùng CASE trả số thứ tự |
Tóm tắt
IF→CASE WHEN; nhánh đầu tiên đúng sẽ dừng.- Sắp điều kiện hẹp trước, rộng sau; luôn có
ELSE. CASEdùng được trongSELECT,WHERE,ORDER BY.IFERROR→NULLIF+COALESCE, không nuốt lỗi thật.- Khi nhánh nhiều, dùng bảng ánh xạ thay vì
CASEdài.
Use ← → to move between lessons