All 40 lessons
Lesson 12 of 40 · SQL Functions
SQL CASE WHEN
By Skillancy Editorial Team
Every example runs on the ShopKart dataset, already loaded in the free SQL Compiler. Click Try it in the SQL Compiler under a query to open it there, then press Run.
CASE WHEN adds if-then-else logic to a query. It checks conditions in order and returns the value for the first one that's true. Analysts use it to bucket numbers into bands, turn codes into labels, and count things conditionally.
Syntax
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result
ENDThere's also a shorter "simple" form for comparing one column to fixed values:
CASE column
WHEN value1 THEN result1
WHEN value2 THEN result2
ELSE default_result
ENDExamples
1. Price bands
SELECT product_name,
price,
CASE
WHEN price >= 10000 THEN 'Premium'
WHEN price >= 2000 THEN 'Mid-range'
ELSE 'Budget'
END AS price_band
FROM products
ORDER BY price DESC
LIMIT 8;Try it in the SQL CompilerResult:
| product_name | price | price_band |
|---|---|---|
| Samsung 43" Smart TV | 31990.00 | Premium |
| Redmi Note 13 Pro | 23999.00 | Premium |
| Women's Silk Saree | 8499.00 | Mid-range |
| Cricket Bat (Kashmir Willow) | 3499.00 | Mid-range |
| Kumkumadi Face Oil | 2995.00 | Mid-range |
| Running Shoes | 2499.00 | Mid-range |
| Prestige Pressure Cooker 5L | 2199.00 | Mid-range |
| Men's Cotton Kurta | 1899.00 | Budget |
(8 rows)
Because CASE stops at the first true condition, a ₹23,999 phone is labelled Premium and never reaches the Mid-range check.
2. Simple CASE to relabel codes
SELECT order_id,
payment_method,
CASE payment_method
WHEN 'COD' THEN 'Cash on Delivery'
WHEN 'UPI' THEN 'UPI'
ELSE 'Online (Card/NetBanking)'
END AS payment_type
FROM orders
LIMIT 5;Try it in the SQL CompilerResult:
| order_id | payment_method | payment_type |
|---|---|---|
| 1001 | UPI | UPI |
| 1002 | Card | Online (Card/NetBanking) |
| 1003 | UPI | UPI |
| 1004 | Card | Online (Card/NetBanking) |
| 1005 | NetBanking | Online (Card/NetBanking) |
(5 rows)
3. Delivery speed
SELECT order_id,
delivery_date - order_date AS days,
CASE
WHEN delivery_date IS NULL THEN 'Not delivered'
WHEN delivery_date - order_date <= 3 THEN 'Fast'
ELSE 'Slow'
END AS delivery_speed
FROM orders
WHERE order_id BETWEEN 1001 AND 1006;Try it in the SQL CompilerResult:
| order_id | days | delivery_speed |
|---|---|---|
| 1001 | 3 | Fast |
| 1002 | 5 | Slow |
| 1003 | 3 | Fast |
| 1004 | NULL | Not delivered |
| 1005 | 3 | Fast |
| 1006 | 4 | Slow |
(6 rows)
Check for NULL first; otherwise NULL days would fall through to ELSE 'Slow'.
4. Conditional counts (CASE inside an aggregate)
This is the most powerful use of CASE. Count orders by outcome in a single row:
SELECT COUNT(*) AS total_orders,
SUM(CASE WHEN status = 'Delivered' THEN 1 ELSE 0 END) AS delivered,
SUM(CASE WHEN status IN ('Cancelled', 'Returned') THEN 1 ELSE 0 END) AS lost
FROM orders;Try it in the SQL CompilerResult:
| total_orders | delivered | lost |
|---|---|---|
| 24 | 16 | 4 |
(1 row)
This pattern is the basis of pivoting data in SQL.
5. Custom sort order
Sort orders by how urgently they need attention, not alphabetically:
SELECT order_id, status
FROM orders
WHERE status <> 'Delivered'
ORDER BY CASE status
WHEN 'Pending' THEN 1
WHEN 'Shipped' THEN 2
WHEN 'Returned' THEN 3
ELSE 4
END,
order_id;Try it in the SQL CompilerResult:
| order_id | status |
|---|---|
| 1023 | Pending |
| 1024 | Pending |
| 1020 | Shipped |
| 1022 | Shipped |
| 1006 | Returned |
| 1015 | Returned |
| 1004 | Cancelled |
| 1012 | Cancelled |
(8 rows)
Common mistakes
- Forgetting
END. EveryCASEmust close withEND. - Wrong condition order.
WHEN price >= 2000beforeWHEN price >= 10000labels everything above ₹2,000 as Mid-range. - Mixed result types. All
THENvalues should be the same type. Don't return a number in one branch and text in another. - No ELSE. Unmatched rows become NULL, which may be what you want, but it should be deliberate.
Practice question
Label each customer as "Early adopter" if they signed up before 2025, otherwise "New". Show name, signup date and the label.
Show solution
SELECT customer_name,
signup_date,
CASE
WHEN signup_date < '2025-01-01' THEN 'Early adopter'
ELSE 'New'
END AS customer_type
FROM customers
ORDER BY signup_date
LIMIT 8;Try it in the SQL CompilerResult:
| customer_name | signup_date | customer_type |
|---|---|---|
| Aarav Sharma | 2024-03-15 | Early adopter |
| Priya Nair | 2024-05-22 | Early adopter |
| Rohan Gupta | 2024-07-01 | Early adopter |
| Sneha Reddy | 2024-08-10 | Early adopter |
| Vikram Singh | 2024-09-05 | Early adopter |
| Ananya Iyer | 2024-11-18 | Early adopter |
| Karan Mehta | 2025-01-09 | New |
| Ishita Das | 2025-02-14 | New |
(8 rows)
Key takeaways
CASE WHEN ... THEN ... ELSE ... ENDis SQL's if-then-else.- Conditions are checked in order; the first true one wins.
- Without
ELSE, unmatched rows return NULL. SUM(CASE WHEN ... THEN 1 ELSE 0 END)counts rows that meet a condition.
Frequently asked questions
What happens if no WHEN condition matches?
CASE returns the ELSE value. If there is no ELSE, it returns NULL.
Does CASE stop at the first matching condition?
Yes. Conditions are checked top to bottom and the first true one wins, so put the most specific conditions first.
Can I use CASE in WHERE, ORDER BY and GROUP BY?
Yes. CASE is an expression, so it can appear anywhere a value can: SELECT, WHERE, ORDER BY, GROUP BY and inside aggregate functions.
Keep learning SQL
One email a week with SQL and analytics guides, new practice questions and cohort dates. No spam, unsubscribe anytime.
Prefer a one-page summary? Download the free SQL cheat sheet (PDF)