SQL Quest
Sign in Français 0 XP Lvl 1
Intermediate

SQL CASE WHEN: write conditions in a query

5 min read · 3 runnable examples · updated October 9, 2026

“If the price is above €100, show premium, otherwise standard.” For this kind of logic, SQL offers the CASE WHEN expression, the equivalent of “if… then… else” in programming languages. You can use it anywhere a value is expected: in the SELECT, the ORDER BY, and even inside a SUM.

Syntax

CASE
  WHEN condition1 THEN value1
  WHEN condition2 THEN value2
  ELSE default_value
END

How it works

SQL tests the WHEN conditions in order and returns the value of the first true condition. If none is true, it returns the ELSE value, or NULL if there is no ELSE. The word END closes the expression; it is often given an alias with AS.

A short form

To compare a single column with several values: CASE statut WHEN 'livrée' THEN 'OK' WHEN 'annulée' THEN 'KO' ELSE '…' END.

Counting based on a condition

SUM(CASE WHEN condition THEN 1 ELSE 0 END) counts the rows that meet a condition. With several expressions of this kind, you get a cross-tab in a single query.

Diagram

produits
nomprix
Écran289
Plaid25
SSD149
result
nomgamme
Écranpremium
Plaidstandard
SSDpremium
CASE WHEN prix >= 100 THEN 'premium' ELSE 'standard' END: a new column is computed based on a condition.

Simplified diagram to show the idea. The examples below use the real SQL Quest practice database (a fictional online shop: see the full schema).

Glossary: the sample database uses French names
clients
customers
commandes
orders
lignes_commande
order lines
produits
products
fournisseurs
suppliers
employes
employees
prenom / nom
first name / last name (or name)
ville
city
pays
country
prix
price
prix_unitaire
unit price
quantite
quantity
categorie
category
date_commande
order date
poste
job title
departement
department
salaire
salary
statut
status: livrée = delivered, expédiée = shipped, en cours = in progress, annulée = cancelled

Examples with their results

1. Create categories

A price range computed for each product.

SELECT nom, prix,
  CASE
    WHEN prix >= 100 THEN 'premium'
    WHEN prix >= 30 THEN 'mid-range'
    ELSE 'budget'
  END AS price_range
FROM produits
ORDER BY prix DESC
LIMIT 8;
Try it in the sandbox
Result
nomprixprice_range
Écran 27"342premium
SSD 1To317premium
Souris sans fil103premium
Webcam HD101premium
Casque gaming98mid-range
Bougie parfumée60.92mid-range
Lampe LED51.74mid-range
Hub USB-C49mid-range

8 rows in total

2. Group on a computed category

The number of customers per age group.

SELECT
  CASE
    WHEN age IS NULL THEN 'unknown'
    WHEN age < 30 THEN 'under 30'
    WHEN age < 50 THEN '30 to 49'
    ELSE '50 and over'
  END AS age_group,
  COUNT(*) AS nb
FROM clients
GROUP BY age_group
ORDER BY nb DESC;
Try it in the sandbox
Result
age_groupnb
50 and over50
30 to 4947
under 3019
unknown4

4 rows in total

3. Count based on a condition

For each year, the total number of orders and the number of cancelled orders.

SELECT strftime('%Y', date_commande) AS annee,
       COUNT(*) AS total,
       SUM(CASE WHEN statut = 'annulée' THEN 1 ELSE 0 END) AS annulees
FROM commandes
GROUP BY annee;
Try it in the sandbox
Result
anneetotalannulees
202319039
202421428
202519625

3 rows in total

Common mistakes

Forgetting END

Every CASE must end with END, otherwise the query causes a syntax error.

Avoid
SELECT nom, CASE WHEN prix > 100 THEN 'expensive' ELSE 'affordable' AS price_range FROM produits;
Correct
SELECT nom, CASE WHEN prix > 100 THEN 'expensive' ELSE 'affordable' END AS price_range FROM produits;

Putting the conditions in the wrong order

The first true condition wins: here, a €300 price is classified “mid-range” because prix >= 30 is tested first.

Avoid
SELECT nom, CASE WHEN prix >= 30 THEN 'mid-range' WHEN prix >= 100 THEN 'premium' END FROM produits;
Correct
SELECT nom, CASE WHEN prix >= 100 THEN 'premium' WHEN prix >= 30 THEN 'mid-range' END FROM produits;

Forgetting the ELSE

Without ELSE, the rows that meet no condition get NULL, which often skews calculations.

Avoid
SELECT SUM(CASE WHEN statut = 'livrée' THEN 1 END) FROM commandes;
Correct
SELECT SUM(CASE WHEN statut = 'livrée' THEN 1 ELSE 0 END) FROM commandes;

Exercises

Try writing the query yourself before opening the solution.

Challenge 1. Show each product with an “availability” column: “out of stock” if the stock is 0, “low” below 20, otherwise “ok”.

Show a solution
SELECT nom, stock, CASE WHEN stock = 0 THEN 'out of stock' WHEN stock < 20 THEN 'low' ELSE 'ok' END AS availability FROM produits;
nomstockavailability
Clavier mécanique105ok
Souris sans fil75ok
Écran 27"102ok
Webcam HD21ok
SSD 1To90ok
Casque gaming37ok
Hub USB-C162ok
Lampe LED15low

29 rows in total · 8 shown

Try it in the sandbox

Challenge 2. For each city, count the customers under 30 and those aged 30 and over.

Show a solution
SELECT ville, SUM(CASE WHEN age < 30 THEN 1 ELSE 0 END) AS under_30, SUM(CASE WHEN age >= 30 THEN 1 ELSE 0 END) AS others FROM clients GROUP BY ville;
villeunder_30others
Bordeaux49
Bruxelles08
Casablanca28
Genève05
Lille36
Lyon111
Marseille19
Montréal37

12 rows in total · 8 shown

Try it in the sandbox
Want more practice?

The interactive exercises are checked automatically, with a tutor who explains your mistakes. A short lesson stays next to the editor.

Do the interactive exercises

Frequently asked questions

Can I use CASE in a WHERE clause?

Yes, but it is rarely needed: a combination of AND and OR is usually easier to read.

Is there an IF function in SQL?

MySQL has IF(condition, a, b) and SQLite has IIF(condition, a, b) since version 3.32. CASE WHEN is the standard version that works everywhere.

Do the THEN values have to be of the same type?

It is strongly recommended. Mixing text and numbers works in SQLite, but causes errors or conversions in other databases.

Read next