Phase 1 · Reading data: SELECT, WHERE and sorting · Topic 1.7

CASE WHEN: if-then logic inside a query

Must know

CASE WHEN condition THEN value … ELSE value END returns a value chosen by the first condition that is true, so a query can label, group or tidy values row by row.

Not started

Step 1 Understand it

Why you need it. Data often needs sorting into buckets — salary bands, "open" or "closed" orders, "new" or "returning" customers — and those labels aren't stored anywhere. builds them inside the . It is also the key to counting several things in one pass (Phase 2) and to .

New words in this topic (tap one to see what it means)

Watch it happen

AnimationCASE WHEN: the first true line wins
Read the animation as text
  1. CASE is SQL's if-else. For each row it tries the WHEN lines from top to bottom and returns the THEN of the first one that is true.
  2. Asha, 95000: salary >= 80000 is true on the first line, so her band is 'high' and CASE stops looking.
  3. Ben, 70000: the first line is false; salary >= 50000 is true, so 'medium'.
  4. Eli, 45000: both tests are false, so ELSE gives 'low'. With no ELSE, he would get NULL.
  5. Every row gets its band. Order matters: if the >= 50000 line came first, Asha would stop there and wrongly get 'medium'.

Picture it

flowchart TD
  R["one row: salary"] --> A{"salary 80000 or more?"}
  A -->|"yes"| H["high"]
  A -->|"no"| B{"salary 50000 or more?"}
  B -->|"yes"| M["medium"]
  B -->|"no"| L["ELSE: low"]
CASE checks its WHEN conditions in order and returns the first match. A that matches nothing gets the ELSE value — or if there is no ELSE.

The idea

CASE is 's if-else. For each row, it checks the WHEN conditions from top to bottom and returns the THEN value of the first one that is true. If none is true, it returns the ELSE value — or NULL if there is no ELSE. CASE is an , so it can go anywhere a value can: in , , , , or inside and . The short form, CASE status WHEN 'shipped' THEN …, compares one with several values.

The shape of it

sql
CASE
  WHEN condition1 THEN value1
  WHEN condition2 THEN value2
  ELSE other_value
END AS new_column

Words in lower case are the parts you fill in.

How it works, step by step

  1. For Asha (95000): salary >= 80000 is true, so the band is 'high', and CASE stops.
  2. For Ben (70000): the first test is false; salary >= 50000 is true, so 'medium'.
  3. For Eli (45000): both tests are false, so ELSE gives 'low'.
  4. If the tests were in the other order (>= 50000 first), Asha would wrongly get 'medium'. Order matters.
  5. END closes the CASE, and names the new column.

Analogy

Sorting post into pigeonholes. You read the address, check the first rule ("London?"), then the next ("Leeds?"), and drop the letter into the first hole that fits. Anything that fits no rule goes into "other" — that is ELSE.

Where the analogy breaks

A postal worker can put one letter in two holes by mistake. CASE never does: it stops at the first true WHEN, so the order of the WHENs matters. Put the strictest test first.

Worked examples

Salary bands

sql
SELECT name, salary,
       CASE
         WHEN salary >= 80000 THEN 'high'
         WHEN salary >= 50000 THEN 'medium'
         ELSE 'low'
       END AS band
FROM employees
ORDER BY salary DESC, name;

8 rows

namesalaryband
Asha95000high
Hana80000high
Ben70000medium
Chen70000medium
Dara60000medium
Fatima52000medium
Eli45000low
Gus38000low

The short form: compare one column

sql
SELECT order_id, status,
       CASE status
         WHEN 'delivered' THEN 'closed'
         WHEN 'cancelled' THEN 'closed'
         ELSE 'open'
       END AS state
FROM orders
WHERE customer_id = 1
ORDER BY order_id;

5 rows

order_idstatusstate
101deliveredclosed
102deliveredclosed
103deliveredclosed
105shippedopen
109deliveredclosed

No ELSE means NULL

sql
SELECT name, CASE WHEN dept_id = 1 THEN 'engineering' END AS team
FROM employees
WHERE salary <= 70000
ORDER BY name;

6 rows

nameteam
Benengineering
Chenengineering
DaraNULL
EliNULL
FatimaNULL
GusNULL

Rows that match no WHEN get NULL. Add an ELSE whenever NULL isn't what you want.

Must-know points

  • CASE returns the THEN value of the first true WHEN, then stops.
  • No ELSE means NULL for rows that match nothing.
  • Always finish with END, and name the result with AS.
  • CASE is an expression: it works in SELECT, WHERE, ORDER BY, GROUP BY and inside .
  • Every THEN should return the same type — all text, or all numbers.

Common mistakes

  • Putting the loose condition first (>= 50000 before >= 80000), so the strict one is never reached.
  • Forgetting END, which gives a syntax error.
  • Writing CASE status WHEN NULL THEN …. The short form uses =, so it never matches NULL. Use CASE WHEN status IS NULL THEN ….

In other databases

  • and also have IF(condition, a, b) / IIF(condition, a, b), and has IIF. CASE works everywhere, so learn CASE.

Step 2 Go further (free, optional)

Optional. The notes above are written to be enough on their own. These free resources give a second explanation and more practice.

Step 3 Practise

Try each one yourself first: out loud, or written and run in the practice box below, which saves every query you run. Then open the answer and compare.

  1. ExplainSay what it does and when to use it, in plain words, with no notes.

    Explain why the order of the WHEN lines matters, using the salary bands.

    Show answer

    CASE checks the WHEN lines from top to bottom and stops at the first one that is true. So the most specific test must come first.

    The right order is WHEN salary >= 80000 THEN 'high', then WHEN salary >= 50000 THEN 'medium', then ELSE 'low'.

    Swap the first two lines and Asha (95,000) meets >= 50000 first. That is true, so she becomes 'medium', and the 'high' line is never reached for anyone. The query below has the lines swapped: nobody is high.

    sql
    SELECT name, salary,
           CASE
             WHEN salary >= 50000 THEN 'medium'
             WHEN salary >= 80000 THEN 'high'
             ELSE 'low'
           END AS band
    FROM employees
    ORDER BY salary DESC, name;

    8 rows

    namesalaryband
    Asha95000medium
    Hana80000medium
    Ben70000medium
    Chen70000medium
    Dara60000medium
    Fatima52000medium
    Eli45000low
    Gus38000low
  2. Writefrom a blank page, then run it

    Write a query that labels each product as 'cheap' (under £10), 'mid' (£10 to £29) or 'premium' (£30 and up), sorted by price.

    Show answer

    Test the cheapest band first; then each line only needs an upper limit. "Under £10" is < 10, and "£10 to £29" is < 30 once the first line has taken the cheap ones.

    sql
    SELECT product_name, price,
           CASE
             WHEN price < 10 THEN 'cheap'
             WHEN price < 30 THEN 'mid'
             ELSE 'premium'
           END AS price_band
    FROM products
    ORDER BY price;

    7 rows

    product_namepriceprice_band
    Pen2cheap
    Notebook5cheap
    Mug8cheap
    Phone case15mid
    Desk lamp25mid
    Backpack30premium
    Headphones40premium
  3. Predictsay it before you run it

    What state does each of Tom's orders get in the short-form example? (Change customer_id to 2 in your head.)

    Show answer

    Tom (customer 2) has two orders, 104 and 108. Both are delivered, so both are 'closed'.

    sql
    SELECT order_id, status,
           CASE status
             WHEN 'delivered' THEN 'closed'
             WHEN 'cancelled' THEN 'closed'
             ELSE 'open'
           END AS state
    FROM orders
    WHERE customer_id = 2
    ORDER BY order_id;

    2 rows

    order_idstatusstate
    104deliveredclosed
    108deliveredclosed
  4. Edge casesSay what happens with NULLs, ties, duplicates or no rows at all, and fix it.

    Order 106 has a NULL amount. Write a CASE that labels orders 'big' (over £100), 'small', or 'unknown' when the amount is missing.

    Show answer

    Test for NULL first. If you don't, NULL > 100 is unknown, not true, so order 106 falls through to ELSE and is wrongly labelled 'small'.

    sql
    SELECT order_id, amount,
           CASE
             WHEN amount IS NULL THEN 'unknown'
             WHEN amount > 100 THEN 'big'
             ELSE 'small'
           END AS size
    FROM orders
    ORDER BY order_id;

    10 rows

    order_idamountsize
    101120big
    10280small
    10345small
    104200big
    105150big
    106NULLunknown
    10760small
    10875small
    10930small
    11033small

Practice box: write and run your answers here

Ctrl/⌘ + Enter runs it. Select part of the query to run only that part.

Step 4 Interview-ready, then prove it

Your interview answer

About 20 to 40 seconds, said out loud.

CASE is SQL's conditional expression: it evaluates WHEN conditions in order and returns the first matching THEN value, or the ELSE value, or NULL if there is no ELSE. Because it is an expression it works anywhere — I use it to bucket values, to sort in a custom order, and most of all inside aggregates, like SUM of CASE WHEN status equals delivered THEN 1, to count several categories in a single pass.

Follow-up questions

What happens when no WHEN matches and there is no ELSE?

CASE returns NULL.

How would you sort orders with pending first, then shipped, then the rest?

ORDER BY CASE status WHEN 'pending' THEN 1 WHEN 'shipped' THEN 2 ELSE 3 END.

Tick each check when you can do it without notes

A topic is finished when you pass all four checks, not when you have read it. Be strict: if you had to look at the notes, it is not ticked yet.

  • Explain Say what it does and when to use it, in plain words, with no notes.
  • Write Write the query from a blank page, then run it to check.
  • Predict Read a query and say which rows it returns before you run it.
  • Edge cases Say what happens with NULLs, ties, duplicates or no rows at all, and fix it.

0 of 4 checks ticked.

Saved in this browser. Back it up or move it to another device.