Cara Menggunakan CASE WHEN di SQL (Dengan 8 Contoh Praktis)
TL;DR
CASE WHEN itu kayak if-else di SQL. Bisa buat kategorisasi data, conditional aggregation, sampai bikin pivot table sederhana. Ada 2 jenis: Simple CASE (cek satu kolom) dan Searched CASE (kondisi kompleks).
Apa Itu CASE WHEN di SQL?
Pernah bingung gimana caranya bikin logika if-else di SQL? Misalnya kamu mau kategorisasi pelanggan jadi "Premium", "Regular", atau "New" berdasarkan total belanja mereka. Nah, di sinilah CASE WHEN jadi andalan kamu.
CASE WHEN itu basically statement conditional di SQL. Fungsinya mirip kayak IF-ELSE di bahasa pemrograman lain. Bedanya, CASE WHEN bisa langsung kamu pakai di dalam query SELECT, UPDATE, bahkan ORDER BY.
Kenapa sih CASE WHEN penting banget? Karena sebagai Data Analyst, kamu pasti sering dapet request kayak gini:
- "Tolong kategorisasi customer berdasarkan spending-nya dong"
- "Bikin kolom status yang isinya 'Aktif' atau 'Tidak Aktif' berdasarkan last login"
- "Hitung total penjualan, tapi pisahin per region ya"
Semua itu bisa diselesaikan pake CASE WHEN. Yuk kita bahas!
Sintaks Dasar CASE WHEN
Ada dua jenis CASE WHEN yang perlu kamu tau:
1. Simple CASE (Cek Satu Kolom)
CASE column_name
WHEN value1 THEN result1
WHEN value2 THEN result2
ELSE default_result
END
Simple CASE dipake kalau kamu cuma mau cek satu kolom dengan beberapa nilai. Gampang sih sebenernya.
2. Searched CASE (Kondisi Kompleks)
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result
END
Searched CASE lebih fleksibel. Kamu bisa bikin kondisi apa aja, termasuk yang pake operator perbandingan (>, <, =) atau kombinasi AND/OR.
Dataset yang Akan Kita Pakai
Buat tutorial ini, kita pakai dataset e-commerce Indonesia. Ceritanya kamu Data Analyst di marketplace yang jualan berbagai produk.
Tabel: customers
| customer_id | nama | kota | total_spending | last_order_date | member_since |
|---|---|---|---|---|---|
| 1 | Budi Santoso | Jakarta | 15000000 | 2024-12-15 | 2022-01-10 |
| 2 | Siti Rahayu | Bandung | 3500000 | 2024-11-20 | 2023-06-15 |
| 3 | Andi Wijaya | Surabaya | 8500000 | 2024-12-10 | 2022-08-22 |
| 4 | Dewi Lestari | Jakarta | 500000 | 2024-06-01 | 2024-05-15 |
| 5 | Rudi Hartono | Medan | 25000000 | 2024-12-18 | 2021-03-05 |
| 6 | Maya Putri | Bandung | 1200000 | 2024-10-05 | 2024-01-20 |
| 7 | Agus Pratama | Semarang | 45000000 | 2024-12-20 | 2020-11-11 |
| 8 | Rina Wati | Jakarta | 6000000 | 2024-08-30 | 2023-02-28 |
Tabel: orders
| order_id | customer_id | order_date | total_amount | status | payment_method |
|---|---|---|---|---|---|
| 101 | 1 | 2024-12-15 | 2500000 | completed | credit_card |
| 102 | 2 | 2024-11-20 | 850000 | completed | bank_transfer |
| 103 | 3 | 2024-12-10 | 1500000 | completed | e_wallet |
| 104 | 4 | 2024-06-01 | 500000 | cancelled | cod |
| 105 | 5 | 2024-12-18 | 5000000 | completed | credit_card |
| 106 | 1 | 2024-12-01 | 3500000 | completed | e_wallet |
| 107 | 7 | 2024-12-20 | 12000000 | pending | bank_transfer |
| 108 | 3 | 2024-12-05 | 2000000 | completed | credit_card |
Contoh 1: Kategorisasi Customer Berdasarkan Spending
Ini contoh paling umum. Kamu mau bikin segmentasi customer berdasarkan total belanja mereka.
SELECT
customer_id,
nama,
total_spending,
CASE
WHEN total_spending >= 20000000 THEN 'Platinum'
WHEN total_spending >= 10000000 THEN 'Gold'
WHEN total_spending >= 5000000 THEN 'Silver'
ELSE 'Bronze'
END AS customer_tier
FROM customers;
Hasil:
| customer_id | nama | total_spending | customer_tier |
|---|---|---|---|
| 1 | Budi Santoso | 15000000 | Gold |
| 2 | Siti Rahayu | 3500000 | Bronze |
| 3 | Andi Wijaya | 8500000 | Silver |
| 4 | Dewi Lestari | 500000 | Bronze |
| 5 | Rudi Hartono | 25000000 | Platinum |
| 6 | Maya Putri | 1200000 | Bronze |
| 7 | Agus Pratama | 45000000 | Platinum |
| 8 | Rina Wati | 6000000 | Silver |
Gampang kan? Yang perlu diinget, urutan kondisi CASE WHEN itu penting. SQL bakal ngecek dari atas ke bawah, dan begitu ketemu kondisi yang TRUE, dia langsung return hasilnya.
Contoh 2: Simple CASE untuk Status Order
Kalau kamu cuma mau cek satu kolom dengan beberapa nilai spesifik, pake Simple CASE aja. Lebih clean.
SELECT
order_id,
customer_id,
total_amount,
status,
CASE status
WHEN 'completed' THEN 'Selesai'
WHEN 'pending' THEN 'Menunggu Pembayaran'
WHEN 'cancelled' THEN 'Dibatalkan'
WHEN 'shipped' THEN 'Dalam Pengiriman'
ELSE 'Status Tidak Dikenal'
END AS status_indonesia
FROM orders;
Hasil:
| order_id | customer_id | total_amount | status | status_indonesia |
|---|---|---|---|---|
| 101 | 1 | 2500000 | completed | Selesai |
| 102 | 2 | 850000 | completed | Selesai |
| 103 | 3 | 1500000 | completed | Selesai |
| 104 | 4 | 500000 | cancelled | Dibatalkan |
| 105 | 5 | 5000000 | completed | Selesai |
| 106 | 1 | 3500000 | completed | Selesai |
| 107 | 7 | 12000000 | pending | Menunggu Pembayaran |
| 108 | 3 | 2000000 | completed | Selesai |
Simple CASE cocok banget buat translate atau mapping nilai. Kodenya jadi lebih readable.
Contoh 3: Conditional Aggregation
Nah ini nih yang sering dipake di reporting. Kamu mau hitung agregasi tapi dengan kondisi tertentu.
Misalnya, kamu mau tau total penjualan per metode pembayaran, tapi cuma yang statusnya completed.
SELECT
payment_method,
COUNT(*) AS total_orders,
SUM(CASE WHEN status = 'completed' THEN total_amount ELSE 0 END) AS completed_revenue,
SUM(CASE WHEN status = 'pending' THEN total_amount ELSE 0 END) AS pending_revenue,
SUM(CASE WHEN status = 'cancelled' THEN total_amount ELSE 0 END) AS cancelled_amount
FROM orders
GROUP BY payment_method;
Hasil:
| payment_method | total_orders | completed_revenue | pending_revenue | cancelled_amount |
|---|---|---|---|---|
| credit_card | 3 | 9500000 | 0 | 0 |
| bank_transfer | 2 | 850000 | 12000000 | 0 |
| e_wallet | 2 | 5000000 | 0 | 0 |
| cod | 1 | 0 | 0 | 500000 |
Keren kan? Dengan satu query, kamu bisa breakdown revenue per status sekaligus.
Contoh 4: Bikin Pivot Table Sederhana
CASE WHEN juga bisa dipake buat bikin pivot table. Misalnya kamu mau liat jumlah customer per tier di setiap kota.
SELECT
kota,
SUM(CASE WHEN total_spending >= 20000000 THEN 1 ELSE 0 END) AS platinum,
SUM(CASE WHEN total_spending >= 10000000 AND total_spending < 20000000 THEN 1 ELSE 0 END) AS gold,
SUM(CASE WHEN total_spending >= 5000000 AND total_spending < 10000000 THEN 1 ELSE 0 END) AS silver,
SUM(CASE WHEN total_spending < 5000000 THEN 1 ELSE 0 END) AS bronze
FROM customers
GROUP BY kota;
Hasil:
| kota | platinum | gold | silver | bronze |
|---|---|---|---|---|
| Jakarta | 0 | 1 | 1 | 1 |
| Bandung | 0 | 0 | 0 | 2 |
| Surabaya | 0 | 0 | 1 | 0 |
| Medan | 1 | 0 | 0 | 0 |
| Semarang | 1 | 0 | 0 | 0 |
Sekarang kamu bisa liat distribusi customer tier per kota dalam satu tabel yang gampang dibaca.
Contoh 5: Handling NULL Values
CASE WHEN juga berguna banget buat handle NULL. Misalnya, kamu mau kasih label khusus buat data yang kosong.
SELECT
customer_id,
nama,
last_order_date,
CASE
WHEN last_order_date IS NULL THEN 'Belum Pernah Order'
WHEN last_order_date >= CURRENT_DATE - INTERVAL '30 days' THEN 'Aktif'
WHEN last_order_date >= CURRENT_DATE - INTERVAL '90 days' THEN 'Kurang Aktif'
ELSE 'Tidak Aktif'
END AS activity_status
FROM customers;
Hasil:
| customer_id | nama | last_order_date | activity_status |
|---|---|---|---|
| 1 | Budi Santoso | 2024-12-15 | Aktif |
| 2 | Siti Rahayu | 2024-11-20 | Kurang Aktif |
| 3 | Andi Wijaya | 2024-12-10 | Aktif |
| 4 | Dewi Lestari | 2024-06-01 | Tidak Aktif |
| 5 | Rudi Hartono | 2024-12-18 | Aktif |
| 6 | Maya Putri | 2024-10-05 | Kurang Aktif |
| 7 | Agus Pratama | 2024-12-20 | Aktif |
| 8 | Rina Wati | 2024-08-30 | Tidak Aktif |
Tips nih: selalu taro kondisi NULL di paling atas kalau kamu mau handle-nya secara khusus. Karena NULL itu tricky, dia ga bisa di-compare pake operator biasa.
Contoh 6: Multiple Conditions dengan AND/OR
Kadang kamu butuh kondisi yang lebih kompleks. Misalnya, kategorisasi customer berdasarkan spending DAN lama membership.
SELECT
customer_id,
nama,
total_spending,
member_since,
CASE
WHEN total_spending >= 20000000 AND member_since < '2022-01-01' THEN 'VIP Loyal'
WHEN total_spending >= 20000000 THEN 'VIP New'
WHEN total_spending >= 5000000 AND member_since < '2023-01-01' THEN 'Regular Loyal'
WHEN total_spending >= 5000000 THEN 'Regular New'
ELSE 'Newcomer'
END AS customer_segment
FROM customers;
Hasil:
| customer_id | nama | total_spending | member_since | customer_segment |
|---|---|---|---|---|
| 1 | Budi Santoso | 15000000 | 2022-01-10 | Regular Loyal |
| 2 | Siti Rahayu | 3500000 | 2023-06-15 | Newcomer |
| 3 | Andi Wijaya | 8500000 | 2022-08-22 | Regular Loyal |
| 4 | Dewi Lestari | 500000 | 2024-05-15 | Newcomer |
| 5 | Rudi Hartono | 25000000 | 2021-03-05 | VIP Loyal |
| 6 | Maya Putri | 1200000 | 2024-01-20 | Newcomer |
| 7 | Agus Pratama | 45000000 | 2020-11-11 | VIP Loyal |
| 8 | Rina Wati | 6000000 | 2023-02-28 | Regular New |
Kombinasi AND/OR bikin segmentasi kamu jadi lebih granular.
Contoh 7: Nested CASE (CASE di Dalam CASE)
Untuk kasus yang super kompleks, kamu bisa nesting CASE WHEN. Tapi hati-hati, jangan terlalu dalam nesting-nya karena bikin query susah dibaca.
SELECT
customer_id,
nama,
kota,
total_spending,
CASE
WHEN kota = 'Jakarta' THEN
CASE
WHEN total_spending >= 10000000 THEN 'Jakarta Premium'
ELSE 'Jakarta Regular'
END
WHEN kota IN ('Bandung', 'Surabaya') THEN
CASE
WHEN total_spending >= 10000000 THEN 'Kota Besar Premium'
ELSE 'Kota Besar Regular'
END
ELSE
CASE
WHEN total_spending >= 10000000 THEN 'Kota Lain Premium'
ELSE 'Kota Lain Regular'
END
END AS geo_segment
FROM customers;
Hasil:
| customer_id | nama | kota | total_spending | geo_segment |
|---|---|---|---|---|
| 1 | Budi Santoso | Jakarta | 15000000 | Jakarta Premium |
| 2 | Siti Rahayu | Bandung | 3500000 | Kota Besar Regular |
| 3 | Andi Wijaya | Surabaya | 8500000 | Kota Besar Regular |
| 4 | Dewi Lestari | Jakarta | 500000 | Jakarta Regular |
| 5 | Rudi Hartono | Medan | 25000000 | Kota Lain Premium |
| 6 | Maya Putri | Bandung | 1200000 | Kota Besar Regular |
| 7 | Agus Pratama | Semarang | 45000000 | Kota Lain Premium |
| 8 | Rina Wati | Jakarta | 6000000 | Jakarta Regular |
Nested CASE berguna, tapi kalau udah terlalu kompleks, mending pake CTE atau temporary table biar lebih clean.
Contoh 8: CASE WHEN di ORDER BY
Yang ini sering dilupain. Kamu bisa pake CASE WHEN di ORDER BY buat custom sorting.
Misalnya, kamu mau urutkan customer berdasarkan tier, tapi urutannya Platinum dulu, baru Gold, Silver, Bronze.
SELECT
customer_id,
nama,
total_spending,
CASE
WHEN total_spending >= 20000000 THEN 'Platinum'
WHEN total_spending >= 10000000 THEN 'Gold'
WHEN total_spending >= 5000000 THEN 'Silver'
ELSE 'Bronze'
END AS customer_tier
FROM customers
ORDER BY
CASE
WHEN total_spending >= 20000000 THEN 1
WHEN total_spending >= 10000000 THEN 2
WHEN total_spending >= 5000000 THEN 3
ELSE 4
END,
total_spending DESC;
Hasil:
| customer_id | nama | total_spending | customer_tier |
|---|---|---|---|
| 7 | Agus Pratama | 45000000 | Platinum |
| 5 | Rudi Hartono | 25000000 | Platinum |
| 1 | Budi Santoso | 15000000 | Gold |
| 3 | Andi Wijaya | 8500000 | Silver |
| 8 | Rina Wati | 6000000 | Silver |
| 2 | Siti Rahayu | 3500000 | Bronze |
| 6 | Maya Putri | 1200000 | Bronze |
| 4 | Dewi Lestari | 500000 | Bronze |
Sekarang hasilnya urut berdasarkan tier, dan di dalam tier yang sama, diurutkan berdasarkan spending dari yang terbesar.
Common Mistakes yang Harus Dihindari
Mistake 1: Lupa END
-- SALAH
SELECT
nama,
CASE
WHEN total_spending >= 10000000 THEN 'Premium'
ELSE 'Regular'
-- Lupa END!
FROM customers;
-- BENAR
SELECT
nama,
CASE
WHEN total_spending >= 10000000 THEN 'Premium'
ELSE 'Regular'
END AS customer_tier
FROM customers;
CASE WHEN HARUS ditutup pake END. Ini error paling sering terjadi.
Mistake 2: Urutan Kondisi yang Salah
-- SALAH (customer 10jt ke atas ikut kelabel 'Silver', padahal harusnya Gold atau Platinum)
SELECT
nama,
CASE
WHEN total_spending >= 5000000 THEN 'Silver'
WHEN total_spending >= 10000000 THEN 'Gold'
WHEN total_spending >= 20000000 THEN 'Platinum'
ELSE 'Bronze'
END AS tier
FROM customers;
-- BENAR (mulai dari kondisi yang paling spesifik)
SELECT
nama,
CASE
WHEN total_spending >= 20000000 THEN 'Platinum'
WHEN total_spending >= 10000000 THEN 'Gold'
WHEN total_spending >= 5000000 THEN 'Silver'
ELSE 'Bronze'
END AS tier
FROM customers;
Begitu spending customer nyampe 5 juta, kondisi pertama langsung TRUE dan dia dapet 'Silver'. Padahal yang belanjanya 25 juta harusnya Platinum. Selalu mulai dari kondisi yang paling spesifik atau nilai yang paling besar.
Mistake 3: Lupa Handle NULL
-- POTENSI MASALAH
SELECT
nama,
CASE
WHEN last_order_date >= '2024-01-01' THEN 'Aktif'
ELSE 'Tidak Aktif' -- NULL juga masuk sini!
END AS status
FROM customers;
-- LEBIH BAIK
SELECT
nama,
CASE
WHEN last_order_date IS NULL THEN 'Belum Pernah Order'
WHEN last_order_date >= '2024-01-01' THEN 'Aktif'
ELSE 'Tidak Aktif'
END AS status
FROM customers;
NULL itu bukan 'Tidak Aktif', jadi handle secara terpisah.
Mistake 4: Mixing Simple dan Searched CASE
-- SALAH (ga bisa dicampur)
SELECT
nama,
CASE status
WHEN 'completed' THEN 'Done'
WHEN total_amount > 1000000 THEN 'Big Order' -- Error!
END
FROM orders;
Kalau udah pake Simple CASE (CASE column), semua kondisi harus cek kolom itu aja. Mau kondisi lain? Pake Searched CASE.
Tips dan Best Practices
1. Selalu Kasih Alias
-- Kurang bagus
SELECT
nama,
CASE WHEN total_spending >= 10000000 THEN 'Premium' ELSE 'Regular' END
FROM customers;
-- Lebih bagus
SELECT
nama,
CASE WHEN total_spending >= 10000000 THEN 'Premium' ELSE 'Regular' END AS customer_tier
FROM customers;
Alias bikin hasil query lebih readable.
2. Gunakan ELSE untuk Default Value
Kalau ga ada ELSE, dan ga ada kondisi yang match, hasilnya bakal NULL. Kadang ini yang kamu mau, kadang nggak. Lebih aman pake ELSE.
3. Pertimbangkan Readability
Kalau CASE WHEN kamu udah panjang banget, pertimbangkan:
- Bikin CTE terpisah
- Pake lookup table
- Atau breakdown jadi beberapa kolom
4. Test dengan Data Edge Case
Selalu test query kamu dengan:
- Nilai NULL
- Nilai di batas kondisi (boundary values)
- Nilai ekstrem (gede atau kecil banget)
Latihan
Coba kerjain query ini pake dataset customers di atas:
Soal: Bikin query yang mengkategorisasi customer berdasarkan kombinasi kota dan aktivitas. Aturannya:
- Customer Jakarta yang order dalam 30 hari terakhir = "Jakarta Aktif"
- Customer Jakarta yang ga order dalam 30 hari = "Jakarta Dormant"
- Customer kota lain yang order dalam 30 hari = "Regional Aktif"
- Customer kota lain yang ga order dalam 30 hari = "Regional Dormant"
Klik untuk lihat hint
Pake Searched CASE dengan kombinasi kondisi kota dan last_order_date. Gunakan CURRENT_DATE untuk cek tanggal.Klik untuk lihat solusi
SELECT
customer_id,
nama,
kota,
last_order_date,
CASE
WHEN kota = 'Jakarta' AND last_order_date >= CURRENT_DATE - INTERVAL '30 days' THEN 'Jakarta Aktif'
WHEN kota = 'Jakarta' THEN 'Jakarta Dormant'
WHEN last_order_date >= CURRENT_DATE - INTERVAL '30 days' THEN 'Regional Aktif'
ELSE 'Regional Dormant'
END AS customer_category
FROM customers
ORDER BY customer_category;
FAQ
Apa bedanya CASE WHEN sama fungsi IF()?
IF() cuma ada di database tertentu kayak MySQL, dan cabangnya cuma dua: kondisi benar atau salah. CASE WHEN itu standar SQL, jadi jalan di PostgreSQL, MySQL, SQL Server, sampai BigQuery. Cabangnya juga bisa banyak sekaligus. Kalau kamu mau query yang portable antar database, pakai CASE WHEN aja.
CASE WHEN bisa dipakai di WHERE dan GROUP BY nggak?
Bisa. Di WHERE, CASE WHEN bantu bikin filter yang kondisinya beda-beda per baris. Di GROUP BY, kamu bisa ngegrupkan data pakai kategori hasil CASE WHEN, misalnya grup berdasarkan tier customer. Tapi hati-hati nih, beberapa database nggak ngizinin alias di GROUP BY, jadi kadang kamu harus tulis ulang CASE WHEN-nya di situ.
Kalau nggak ada kondisi yang cocok dan nggak ada ELSE, hasilnya apa?
Hasilnya NULL. SQL nggak bakal error. Dia diem-diem kasih NULL buat baris yang nggak match kondisi mana pun. Ini sering bikin bingung pas hasil agregasi nggak sesuai ekspektasi. Makanya lebih aman selalu kasih ELSE dengan default value, misalnya 'Lainnya' atau 0.
Berapa banyak kondisi WHEN yang boleh dalam satu CASE?
Secara teknis nggak ada batas yang bakal kamu tabrak di kerjaan sehari-hari. Puluhan kondisi WHEN pun jalan. Tapi kalau udah lebih dari 5-7 kondisi, query jadi susah dibaca dan di-maintain. Mending pindahin mapping-nya ke lookup table terus JOIN, atau pecah pakai CTE biar lebih rapi.
Kesimpulan
Nah, sekarang kamu udah paham kan gimana caranya pake CASE WHEN? Inget poin-poin ini:
- CASE WHEN itu if-else-nya SQL
- Ada Simple CASE (cek satu kolom) dan Searched CASE (kondisi bebas)
- Urutan kondisi penting, mulai dari yang paling spesifik
- Selalu tutup dengan END
- Handle NULL secara eksplisit
- Bisa dipake di SELECT, WHERE, ORDER BY, bahkan di dalam fungsi agregasi
CASE WHEN itu tool serba bisa. Mau bikin segmentasi, kategorisasi, pivot table, atau conditional aggregation, semua bisa. Latihan yang banyak ya!
Selanjutnya
Kalau kamu udah paham CASE WHEN, next step-nya:
- CTE (Common Table Expression) - buat query yang lebih clean
- Window Functions - analisis data yang lebih advanced
- Cohort Analysis - analisis retention user
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel Terkait
7 SQL Client Gratis Terbaik buat Analis Data (2026)
Nggak perlu bayar buat nulis query. Ini 7 SQL client gratis yang beneran dipakai analis, plus kelebihan dan kekurangannya masing-masing.
SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim
Sepuluh aturan SQL style guide yang bikin query kamu kebaca sama tim, dan sama kamu sendiri 6 bulan lagi. Lengkap dengan contoh sebelum-sesudah.
Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya
Contoh soal take-home test SQL yang beneran dipakai perusahaan, dikerjain step by step, dari baca soal, nulis query, sampai nyusun insight yang bikin recruiter nengok.