Use a CASE expression: CASE WHEN total >= 50 THEN 'big' ELSE 'small' END AS size. It is standard SQL and runs on PostgreSQL, MySQL, SQL Server, SQLite and Oracle. MySQL's IF() and SQL Server's IIF() are shorter, but each works only in some databases.
A SELECT can't contain an IF statement, but it can contain an expression that picks a value by condition, and in SQL that expression is CASE. It goes anywhere a value can go: the column list, ORDER BY, WHERE, or inside SUM and COUNT. The sections below cover the two forms of CASE, how to combine conditions with OR and IN, and the short functions for the common cases. The examples run on SQLite; the table in section 6 gives the PostgreSQL, MySQL and SQL Server forms. Hit Run on any of them, then edit the query and run it again.
1CASE WHEN … THEN … ELSE … ENDRecommended
The searched CASE lists conditions after WHEN and the value to return after each THEN. The database checks the branches from top to bottom and returns the value of the first one that is true; the rest are skipped. ELSE is the value when nothing matches, and END closes the expression. Give the result a column name with AS.
Output
In the first query order 3 (250.0) passes both tests and gets large, because that branch comes first. The second query puts the wider test first, so 250.0 stops at medium and the large branch can never fire. Order the branches from the most specific to the most general. It also has no ELSE, so the two orders that match no branch get NULL. Write an ELSE whenever NULL isn't the value you want.
2Simple CASE: match one value against a list
When every branch compares the same column with a constant, the simple form is shorter: name the column once after CASE, then list the values after each WHEN. Each branch is an equality test, status = 0, status = 1 and so on, and that is where its limits come from.
Output
Ticket 4 gets other, not unset: WHEN NULL tests status = NULL, which is never true, not even when status is NULL. The second query switches to the searched form, where status IS NULL works and ticket 4 gets unset. Use the simple form for plain value lookups; anything else needs the searched form.
3OR, AND and IN inside a WHEN
A searched WHEN takes any condition you could write in a WHERE clause, so OR, AND, IN, LIKE and BETWEEN all work there. If you were told "OR is not supported with CASE", the query used the simple form, CASE country WHEN 'US' OR 'CA', where each WHEN holds a value, not a condition.
Output
The first query sorts Ana into NA adult, Ben (17) into NA minor and the others into elsewhere. In the second, 'US' OR 'CA' is worked out first, as one false value, and every country is compared with that, so even Ana lands in elsewhere. SQLite and MySQL run that query and return wrong rows without an error (MySQL only adds warnings); SQL Server stops with a syntax error near OR, and PostgreSQL rejects it with invalid input syntax for type boolean. For several values in the simple form, repeat the branch (WHEN 'US' THEN … WHEN 'CA' THEN …) or switch to WHEN country IN ('US', 'CA').
4CASE in ORDER BY and inside aggregates
Because CASE is just an expression, it works outside the column list too. In ORDER BY it maps text to numbers, which gives a custom sort order that alphabetical sorting can't. Inside SUM or COUNT it counts only the rows that meet a condition, so one query returns several counts side by side. Count rows with a condition covers that pattern in depth.
Output
The tasks come back high, medium, low, with name breaking ties inside each priority. The summary row shows 5 tasks, 2 done and 2 high. The two counting styles do the same job: SUM(CASE … THEN 1 ELSE 0 END) adds ones and zeros, while COUNT(CASE … THEN 1 END) relies on the missing ELSE giving NULL, which COUNT skips.
5Shortcuts: iif(), COALESCE and NULLIF
Three functions cover the most common two-way choices in less text. iif(cond, a, b) returns a when the condition is true and b otherwise; it exists in SQLite 3.32+ and SQL Server 2012+. COALESCE(a, b) returns the first argument that isn't NULL, and NULLIF(a, b) returns NULL when the two are equal. Both are standard SQL and run everywhere.
Output
iif marks the ink as sold out. COALESCE shows - for the two items with no note. NULLIF(qty, 0) turns the ink's zero quantity into NULL, so 9.0 / NULL gives NULL instead of a division by zero. Each is shorthand for a CASE: COALESCE(note, '-') means CASE WHEN note IS NOT NULL THEN note ELSE '-' END. Recent SQLite versions (3.48+) also accept if() as another name for iif().
6Other databases
CASE is the one form every database accepts, so it is the safe choice for code that has to move between them. The shorter functions are vendor extensions. PostgreSQL has neither IF() nor IIF() in a query, only CASE (its IF … THEN … END IF exists only inside PL/pgSQL functions). Oracle also uses CASE. Each snippet below was run on PostgreSQL 18, MySQL 8.4 and SQL Server (Babelfish).
| Syntax | Database | Notes |
|---|---|---|
| CASE WHEN c THEN a ELSE b END | PostgreSQL, MySQL, SQL Server, SQLite | Standard SQL; works everywhere |
| IF(c, a, b) | MySQL; SQLite 3.48+ | PostgreSQL: function if(…) does not exist; SQL Server: syntax error |
| IIF(c, a, b) | SQL Server 2012+; SQLite 3.32+ | MySQL: FUNCTION IIF does not exist; PostgreSQL: function iif(…) does not exist |
| IF … ELSE … | SQL Server | A T-SQL statement that picks which statement runs; not allowed inside a SELECT |
| COALESCE(a, b), NULLIF(a, b) | PostgreSQL, MySQL, SQL Server, SQLite | Standard SQL for the NULL cases |
Frequently asked questions
Is there an IF function I can use in a SQL SELECT?
Not one that works everywhere. MySQL has IF(cond, a, b), SQL Server 2012+ has IIF(cond, a, b) and SQLite 3.32+ has iif(), but PostgreSQL has neither and fails with function iif(boolean, unknown, unknown) does not exist. CASE WHEN cond THEN a ELSE b END runs on all of them, so use it unless the query will only ever run on one database.
Why do I get an error when I use OR in a CASE statement?
You are using the simple form, CASE country WHEN 'US' OR 'CA' THEN …, where each WHEN holds a value to compare with, not a condition. SQL Server reports a syntax error near OR, and SQLite and MySQL run it but return wrong rows. Use the searched form instead: CASE WHEN country = 'US' OR country = 'CA' THEN …, or CASE WHEN country IN ('US', 'CA') THEN ….
What does CASE return when no WHEN matches?
The ELSE value, or NULL when there is no ELSE. Leaving out ELSE is fine on purpose, for example inside COUNT(CASE WHEN … THEN 1 END), where the NULLs are skipped. Elsewhere, write an ELSE so a missing branch shows up as a value you chose.
Why does WHEN NULL never match in a CASE?
The simple form CASE status WHEN NULL THEN … compares status = NULL, and a comparison with NULL is never true. Use the searched form with IS NULL: CASE WHEN status IS NULL THEN 'unset' … END.
Can the THEN branches return different types?
In SQLite they can, because a column holds any type: CASE WHEN total >= 50 THEN total ELSE 'none' END returns 80 for one row and none for another. PostgreSQL and SQL Server pick one result type for the whole expression and fail with invalid input syntax for type integer: "none". Convert the numbers to text first so every branch returns the same type; on PostgreSQL and SQL Server THEN CAST(total AS VARCHAR(10)) fixes it.
What is the difference between IF…ELSE and CASE in SQL Server?
IF … ELSE is a T-SQL control-flow statement: it decides which whole statement runs, such as IF (SELECT COUNT(*) FROM orders WHERE total >= 50) > 0 SELECT 'has big orders' ELSE SELECT 'no big orders'. CASE and IIF() are expressions that return a value for each row inside a query. To change a value per row in a SELECT, use CASE or IIF().
Run it yourself
Open any of these in the SQLite playground to change the conditions and run them again.
SQLite playground