Menu
Try in Playground

SQLite CASE Expressions: WHEN, THEN, ELSE, and IIF

How CASE works in SQLite — simple and searched forms, using it in SELECT, ORDER BY, and WHERE, plus when to reach for IIF instead.

This page includes runnable editors — edit, run, and see output instantly.

CASE Is SQL's If/Else

CASE is how you put conditional logic inside a query. It walks through WHEN branches in order, picks the first one that matches, and returns the value after THEN. If nothing matches, it returns the ELSE value — or NULL if you didn't write one.

The important word is expression. CASE produces a value, so it goes anywhere a value is allowed: a SELECT column, an ORDER BY key, the right-hand side of a comparison, an argument to a function.

That's the whole shape: CASE, one or more WHEN ... THEN ..., optional ELSE, then END. The END is mandatory — forgetting it is the most common typo.

A Realistic Example

Say you've got an orders table and want to label each row by size. Build a small one inline so you can run the query:

Branches are checked top-down. The first match wins, so order them from most specific to most general. The ELSE catches everything that didn't match — without it, 1200.00 would come back as NULL instead of 'large'.

Searched vs Simple

What you saw above is the searched form: each WHEN has its own boolean condition. There's a shorter form when you're comparing one expression to several constants — the simple form:

The expression after CASE is evaluated once and compared with = against each WHEN value. Cleaner when you're doing equality lookups on a single column.

One catch: simple CASE uses =, and NULL = NULL is not true in SQL. If status could be NULL, the 'A'/'B'/'C' branches won't match it — you'd hit ELSE. To handle NULL explicitly, switch to searched form and use WHEN status IS NULL THEN ....

CASE in ORDER BY

ORDER BY takes any expression, so CASE works fine there. Useful when you want a custom sort order that doesn't match alphabetical or numeric order:

'high' < 'low' < 'medium' alphabetically, which is useless for triage. Mapping each priority to a number through CASE gives you the order you actually want. The trailing , id breaks ties stably.

CASE in WHERE

You can put CASE inside WHERE, but most of the time you don't need to — chained AND/OR is clearer. Where it shines is when the condition itself depends on another value:

Sale items qualify under 20, regular items under 30. The threshold itself is conditional. Without CASE you'd have to write (on_sale = 1 AND price < 20) OR (on_sale = 0 AND price < 30) — same result, more noise.

CASE Inside Aggregates

This is where CASE earns its keep. Combine it with SUM or COUNT to compute totals over a subset of rows in a single pass — the SQL equivalent of "count how many of these match":

The CASE returns 1 for matching rows and 0 otherwise, so SUM becomes a conditional count. The same trick works for revenue — return total on the matching rows and 0 everywhere else. One scan of the table, several conditional aggregates.

IIF: The Two-Branch Shortcut

For a single condition with two outcomes, SQLite has IIF(cond, when_true, when_false). It's pure shorthand for CASE WHEN cond THEN when_true ELSE when_false END:

Use IIF when the logic is binary and reads better as one line. Switch to CASE once you have three or more branches, need to handle NULL separately, or want the fall-through ordering of multiple WHEN clauses.

Pitfalls Worth Knowing

A few things that bite people:

  • Forgetting END. CASE opens a block; END closes it. SQLite will give you a parse error well after the actual mistake.
  • No ELSE means NULL. If none of your WHEN branches match and you skipped ELSE, the result is NULL. Sometimes that's what you want; usually it isn't.
  • Branch order matters. With searched form, the first matching WHEN wins. Putting WHEN total < 500 before WHEN total < 100 means the second branch is unreachable.
  • Type mixing. Each branch can return a different type, and SQLite won't complain — but downstream code might. Try to keep all branches returning compatible types (all text, all numeric).
  • Simple CASE and NULL. As mentioned: simple form uses =, which never matches NULL. Use searched form when nulls are in play.

Next: String Functions

CASE lets you branch on values; the next chapter starts on transforming values. String functions — UPPER, LOWER, SUBSTR, REPLACE, LIKE patterns — handle the day-to-day work of cleaning and reformatting text columns. That's up next.

Frequently Asked Questions

What is a CASE expression in SQLite?

A CASE expression is SQL's version of if/else — it evaluates conditions and returns a value. It's an expression, not a statement, which means you can use it anywhere a value is allowed: in SELECT, WHERE, ORDER BY, UPDATE, even inside aggregates. Each branch has the form WHEN condition THEN value, with an optional ELSE at the end.

What's the difference between simple and searched CASE in SQLite?

A simple CASE compares one expression against several values: CASE status WHEN 'A' THEN ... WHEN 'B' THEN ... END. A searched CASE evaluates a separate boolean per branch: CASE WHEN price > 100 THEN ... WHEN qty = 0 THEN ... END. Searched form is more flexible — it can mix columns, operators, and NULL checks freely.

When should I use IIF instead of CASE in SQLite?

IIF(cond, a, b) is shorthand for CASE WHEN cond THEN a ELSE b END. Use IIF for two-branch logic where it reads cleaner. Reach for CASE once you have three or more branches, want fall-through ordering, or need to handle NULL explicitly with WHEN col IS NULL.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED