SQL for Data Science › Chapter 10

Chapter 10

CASE: if / else inside a query

4:42:00 → 4:48:00CASE WHEN … THEN … ELSE … ENDShort but frequently used

Every programming language has if/else. In SQL it's the CASE statement: it lets a query produce different output values depending on conditions, which is perfect for turning numbers into labels.

The class example: box-office verdicts

Compute each Bollywood movie's profit (worldwide − budget, in ₹ crore) and label it:

ProfitVerdict
below 0Flop
0 to 25 croreAverage
25 to 100 croreHit
above 100 croreSuperhit
Try the logic
Drag the profit and watch which WHEN fires.
Flop
< 0
Average
0–25
Hit
25–100
Superhit
> 100
SELECT title,
       worldwide - budget AS profit,
       CASE
           WHEN worldwide - budget > 100 THEN 'Superhit'
           WHEN worldwide - budget > 25  AND worldwide - budget <= 100 THEN 'Hit'
           WHEN worldwide - budget >= 0  AND worldwide - budget <= 25  THEN 'Average'
           ELSE 'Flop'
       END AS verdict
FROM movies;

Anatomy of CASE

  • Starts with CASE, ends with END; give the result a name with AS.
  • Each WHEN condition THEN value is an "if / else-if". They are checked top to bottom, and the first true one wins.
  • ELSE catches everything else. Without it, unmatched rows get NULL.
  • The whole CASE is just an expression, so it sits in the SELECT list like any column.
Shorter, thanks to top-to-bottom order

Because earlier WHENs have already caught the bigger values, the lower bounds are redundant:

SELECT title,
       CASE
           WHEN worldwide - budget > 100 THEN 'Superhit'
           WHEN worldwide - budget > 25  THEN 'Hit'
           WHEN worldwide - budget >= 0  THEN 'Average'
           ELSE 'Flop'
       END AS verdict
FROM movies;

Going further (my additions)

How many movies fall in each verdict? Group by the CASE expression:

SELECT CASE
           WHEN worldwide - budget > 100 THEN 'Superhit'
           WHEN worldwide - budget > 25  THEN 'Hit'
           WHEN worldwide - budget >= 0  THEN 'Average'
           ELSE 'Flop'
       END AS verdict,
       COUNT(*) AS movies
FROM movies
GROUP BY verdict
ORDER BY movies DESC;

Count different things in one pass by putting CASE inside an aggregate:

SELECT pclass,
       SUM(CASE WHEN sex = 'female' THEN 1 ELSE 0 END) AS women,
       SUM(CASE WHEN sex = 'male'   THEN 1 ELSE 0 END) AS men
FROM train
GROUP BY pclass;

When you're only matching exact values of one column, there's a shorter form:

SELECT name,
       CASE embarked
           WHEN 'S' THEN 'Southampton'
           WHEN 'C' THEN 'Cherbourg'
           WHEN 'Q' THEN 'Queenstown'
           ELSE 'Unknown'
       END AS port
FROM train;
-- Drama first, then Action, then everything else
SELECT title, genre FROM movies
ORDER BY CASE genre WHEN 'Drama' THEN 1 WHEN 'Action' THEN 2 ELSE 3 END, title;

You've also seen CASE in Practice 1, Q7 (Titanic family size).

SQL lab

CASE lab · tables: movies, train

Try next: survival rate per age group (wrap the CASE in a GROUP BY), or label movies by runtime as "short / standard / epic".

Conceptual questions

These check whether you understand why, not just what. Several go one step beyond the video.

Why does SUM(CASE WHEN sex = 'female' THEN 1 ELSE 0 END) count women?

This "conditional aggregation" pattern builds pivot-style reports in one query.

Could you use WHERE instead of CASE to produce the four verdict labels in one result?

WHERE filters; CASE computes. You'd need four separate queries with WHERE.

In the verdict query, what label does a NULL profit (unknown budget) get?

That's misleading. Add WHEN profit IS NULL THEN 'Unknown' first.