Skip to content

Beginner: asking questions · Functions, CASE and NULL · topic 14 of 62 · 30 min

CASE expressions

Explanation

CASE is SQL's "if this, then that". It checks conditions in order and returns the value of the first one that is true, or the ELSE value, or NULL when there is no ELSE. Use it to put values into bands (grades, salary bands, price bands), to turn codes into words, and in ORDER BY to sort in a custom order.

Why CASE?

Many reports need a label that is not stored: a grade from marks, "Low stock" from a number, "In progress" from a status. You could work it out in the app, but then every app and report has to repeat the rules. CASE puts the rule in the query, and the database applies it to every row.

Searched CASE

The searched CASE has a list of WHEN conditions. The database checks them from top to bottom, and the first true one wins; the rest are skipped. If none is true, ELSE gives the value. The whole thing ends with END and gives one value, so you can name it with AS.

sql
SELECT name, marks,
       CASE
         WHEN marks IS NULL THEN 'Absent'
         WHEN marks >= 85   THEN 'A'
         WHEN marks >= 70   THEN 'B'
         WHEN marks >= 50   THEN 'C'
         ELSE 'D'
       END AS grade
FROM students;
-- Asha Verma  | 76   | B
-- Priya Nair  | 91   | A
-- Sneha Patil | NULL | Absent
-- Arjun Reddy | 45   | D   ... 8 rows
Because the checks go in order, WHEN marks >= 70 only sees students below 85. No need to write marks >= 70 AND marks < 85.
Think of it like this: CASE is like the fee counter at a railway station: "senior citizen? concession. Student with pass? concession. Child under 5? free. Everyone else: full fare." The clerk stops at the first rule that fits.

Order of the WHENs matters

sql
SELECT name, marks,
       CASE WHEN marks >= 50 THEN 'Pass'
            WHEN marks >= 85 THEN 'Distinction'
            ELSE 'Fail' END AS result
FROM students WHERE id IN (3, 6);
-- Priya Nair  | 91 | Pass        <- never reaches Distinction
-- Arjun Reddy | 45 | Fail
Put the narrowest (highest) band first when the bands overlap.

Simple CASE

When you compare one column with several fixed values, the simple CASE is shorter: write the column once after CASE, then WHEN value THEN result.

sql
SELECT id, status,
       CASE status WHEN 'Delivered' THEN 'Done'
                   WHEN 'Cancelled' THEN 'Closed'
                   ELSE 'In progress' END AS stage
FROM orders;
-- 101 | Delivered | Done
-- 104 | Cancelled | Closed
-- 105 | Shipped   | In progress   ... 8 rows
Careful: A simple CASE uses =, so CASE marks WHEN NULL THEN ... never matches, because NULL = NULL is unknown. To test for NULL, use the searched form: WHEN marks IS NULL THEN ...

ELSE and NULL

If no WHEN is true and there is no ELSE, CASE gives NULL. Sometimes that is what you want (a blank "alert" column for products that are fine). Sometimes it hides a bug. And watch the other way round: in a grade CASE without a NULL check, a student with no marks fails every comparison and falls into ELSE, getting a D she never earned.

sql
SELECT name, stock,
       CASE WHEN stock = 0  THEN 'Out of stock'
            WHEN stock < 15 THEN 'Low' END AS alert
FROM products;
-- Basmati Rice 5kg    | 40 | NULL
-- Steel Tiffin Box    | 12 | Low
-- Power Bank 10000mAh | 0  | Out of stock   ... 8 rows

CASE in ORDER BY: a custom order

Statuses sorted A to Z come out Cancelled, Delivered, Placed, Shipped, which is not how anyone thinks about an order. Give each status a number with CASE in ORDER BY, and sort by that number. The number never appears in the result.

sql
SELECT id, status FROM orders
ORDER BY CASE status WHEN 'Placed'    THEN 1
                     WHEN 'Shipped'   THEN 2
                     WHEN 'Delivered' THEN 3
                     WHEN 'Cancelled' THEN 4 END,
         id;
-- 107 Placed, 108 Placed, 105 Shipped, 101 Delivered, ... 104 Cancelled

CASE works almost anywhere

CASE is an expression, so it can go wherever a value can: in SELECT, WHERE, ORDER BY, inside ROUND, and, in the next module, inside SUM and COUNT to build pivot tables. All results of one CASE should be the same type; PostgreSQL refuses to mix text and numbers in one CASE, while SQLite allows it.

Common mistakes

  • Forgetting END. The error is usually "near FROM: syntax error". Every CASE ends with END.
  • Wide bands first: WHEN marks >= 50 before WHEN marks >= 85 means nobody gets the top band. Order from narrowest to widest.
  • No NULL check, so missing values land in ELSE. Add WHEN col IS NULL THEN ... as the first line.
  • Writing CASE col WHEN NULL. It never matches; use CASE WHEN col IS NULL.
  • Leaving gaps between bands, like < 500 and > 500, so exactly 500 gets NULL. Use >= and < consistently.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

CASE expressions · 1/7

CASE expressions

CASE is SQL's if-then-else. It gives a label or value that is not stored in the table.

Prefer a video by a teacher? Find free videos on “sql case when expression tutorial order by case” on YouTube ↗

In real life: Salary bands in an HR report

HR teams often report pay in bands rather than exact salaries, so the report can be shared more widely without showing anyone's exact pay. A CASE turns each monthly salary into Junior, Middle or Senior, and the same CASE in GROUP BY (module 4) counts people per band.

sql
SELECT name, salary,
       CASE WHEN salary >= 150000 THEN 'Senior'
            WHEN salary >= 90000  THEN 'Middle'
            ELSE 'Junior' END AS band
FROM employees;
Meera Iyer (250000) is Senior; Rahul Sharma (120000) is Middle; Sandeep Rao (60000) is Junior.

Practice (0/3 done)

Task 1 · Code · SQL

Give every student a grade. Return name, marks and grade: 'Absent' when marks is NULL, 'A' for 85 or more, 'B' for 70 to 84, 'C' for 50 to 69, otherwise 'D'.

Task 2 · Code · SQL

The support team wants orders in workflow order: Placed first, then Shipped, then Delivered, then Cancelled; inside each status by id. Return id and status.

Task 3 · Code · SQL

Put products into price bands. Return name, price and band: 'Budget' below 500, 'Mid-range' from 500 to below 1500, 'Premium' for 1500 and above.

Quick quiz

Question 1

1.What does CASE WHEN 72 >= 50 THEN 'C' WHEN 72 >= 70 THEN 'B' ELSE 'D' END return?

Question 2

2.A CASE has no ELSE and no WHEN matches. What is the result?

Question 3

3.Why does CASE marks WHEN NULL THEN 'Absent' END never return Absent?

Question 4

4.You want statuses in the order Placed, Shipped, Delivered, Cancelled. What do you write?

Question 5

5.A grade CASE has no IS NULL check and ends with ELSE 'D'. What grade does a student with NULL marks get?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does CASE WHEN 72 >= 50 THEN 'C' WHEN 72 >= 70 THEN 'B' ELSE 'D' END return?

Answer: 'C'

The first true WHEN wins, and 72 >= 50 is checked first.

A CASE has no ELSE and no WHEN matches. What is the result?

Answer: NULL

Without ELSE, a CASE that matches nothing gives NULL.

Why does CASE marks WHEN NULL THEN 'Absent' END never return Absent?

Answer: A simple CASE compares with =, and NULL = NULL is unknown

Use a searched CASE: WHEN marks IS NULL THEN ...

You want statuses in the order Placed, Shipped, Delivered, Cancelled. What do you write?

Answer: ORDER BY a CASE that gives each status a number

Alphabetical order is not the business order; CASE maps each status to its position.

A grade CASE has no IS NULL check and ends with ELSE 'D'. What grade does a student with NULL marks get?

Answer: 'D'

Every comparison with NULL is unknown, so the row falls through to ELSE.

A switch case has code but no break. What happens?Related

Answer: Compile error: control cannot fall through

C# does not allow fall-through from a non-empty case (error CS0163).

From Decisions: if, else, switch and switch expressions

What does SUM(CASE WHEN status = 'Placed' THEN 1 ELSE 0 END) give?Related

Answer: The number of rows with status Placed

Matching rows add 1, the others add 0.

From Conditional aggregation and string aggregation

const stock = 0; if (stock) { A } else { B }. Which runs?Related

Answer: B

0 is falsy, so the else branch runs, even though 0 is a real stock value.

From Decisions with if and else

What is marks + 5 when marks is NULL?Related

Answer: NULL

Arithmetic with NULL gives NULL.

From SELECT, columns, aliases and expressions

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Functions, CASE and NULL” before its exam: NULL: the missing value.
  2. Module 3 exam: Functions, CASE and NULL · 15 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Aggregation: GROUP BY and HAVING. 62 topics left in the course before the final exam.

← Previous: Working with dates