DHDataHọc
TheoryLesson 4/84 min read+10 XP

IF và CASE WHEN

Bạn sẽ học được

  • Chuyển IF lồng nhau sang CASE WHEN.
  • Xử lý nhiều nhánh và giá trị mặc định.
  • Dùng CASE trong SELECT, WHERE và ORDER BY.
  • Ánh xạ IFERROR sang COALESCE và 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.

ExcelSQL
=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

code
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:

code
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:

code
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ành NULL, tránh chia cho 0.
  • COALESCE(x, 0) thay NULL bằng giá trị mặc định.
code
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

code
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:

code
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ạ:

code
-- 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

  1. Viết CASE phân nhóm giá trị đơn thành Lớn/Trung bình/Nhỏ.
  2. Đảo thứ tự WHEN và quan sát kết quả thay đổi.
  3. Dùng CASE sắp xếp trạng thái theo thứ tự nghiệp vụ.
  4. Tính tỷ lệ bán ra với NULLIF để tránh chia cho 0.
  5. Đếm khách thiếu email bằng cả IS NULL và chuỗi rỗng.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Mọi dòng vào nhánh đầuWHEN rộng đặt trướcSắp từ hẹp đến rộng
Kết quả NULL bất ngờThiếu ELSEThêm nhánh mặc định
Chia cho 0Mẫu số bằng 0NULLIF(mau_so, 0)
Lỗi bị che mấtBắt quá rộng như IFERRORChỉ xử lý NULL, để lỗi thật nổi lên
Chuỗi rỗng không bị bắtChỉ kiểm tra IS NULLThêm trim(cot) = ''
CASE dài khó sửaQuá nhiều nhánhChuyển sang bảng ánh xạ
Sắp xếp sai thứ tựSắp theo chuỗiDù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.
  • CASE dùng được trong SELECT, 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ì CASE dài.

Use ← → to move between lessons