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.CASEopens a block;ENDcloses it. SQLite will give you a parse error well after the actual mistake. - No
ELSEmeansNULL. If none of yourWHENbranches match and you skippedELSE, the result isNULL. Sometimes that's what you want; usually it isn't. - Branch order matters. With searched form, the first matching
WHENwins. PuttingWHEN total < 500beforeWHEN total < 100means 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
CASEandNULL. As mentioned: simple form uses=, which never matchesNULL. 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.