CASE
Sometimes you'll need to do different things based on if a value is NULL or not.
One useful keyword for that is CASE.
Before we look at that with NULL, let's look at CASE by itself.
If-Then Logic
CASE gives you "if this then that" type of logic.
Let's look at an example with the numbers table.
| column_name | type |
|---|---|
x | INTEGER |
SELECT
x,
CASE
WHEN x % 2 = 0 THEN 'even'
ELSE 'odd'
END AS parity
FROM numbers;
| x INTEGER | parity TEXT |
|---|---|
1 | odd |
2 | even |
3 | odd |
4 | even |
5 | odd |
Case expressions are delimited by the keywords CASE and END.
In between, you can have 1 or more WHEN THEN clauses.
The WHEN expression must evaluate to a boolean.
If TRUE, the corresponding THEN expression becomes the chosen value of the case expression.
Optionally, you can have an ELSE clause with a final expression to be chosen if none of the other WHEN clauses are TRUE.
Notice that I call it a "case expression" and not a "case clause".
This is an important distinction because expressions are things that go inside a clause, like in a SELECT or WHERE clause.
Here is an example with multiple WHENs where we play the famous children's game "FizzBuzz".
SELECT
x,
CASE
WHEN x % 15 = 0 THEN 'FizzBuzz'
WHEN x % 5 = 0 THEN 'Buzz'
WHEN x % 3 = 0 THEN 'Fizz'
ELSE x
END AS output
FROM numbers;
error: invalid input syntax for type integer: "FizzBuzz"Wait!! There's an error?
Type Casting
The problem with the above example is that a CASE expression expects every case to return the same type.
We can't have some cases return text and some integers.
So, we need the ability to convert x to TEXT instead of INTEGER.
You can do that with CAST.
It looks like this: CAST(some_value AS OTHER_TYPE).
SELECT
x,
CASE
WHEN x % 15 = 0 THEN 'FizzBuzz'
WHEN x % 5 = 0 THEN 'Buzz'
WHEN x % 3 = 0 THEN 'Fizz'
ELSE CAST(x AS TEXT)
END AS output
FROM numbers;
| x INTEGER | output TEXT |
|---|---|
1 | 1 |
2 | 2 |
3 | Fizz |
4 | 4 |
5 | Buzz |
Postgres-Specific Casting
CAST is part of standardized SQL.
It should work on any SQL database.
However, Postgres has its own alternative.
Instead of CAST(x AS TEXT), you can use x::TEXT.
SELECT
x,
CASE
WHEN x % 15 = 0 THEN 'FizzBuzz'
WHEN x % 5 = 0 THEN 'Buzz'
WHEN x % 3 = 0 THEN 'Fizz'
ELSE x::TEXT
END AS output
FROM numbers;
| x INTEGER | output TEXT |
|---|---|
1 | 1 |
2 | 2 |
3 | Fizz |
4 | 4 |
5 | Buzz |
This is something in programming that we call "syntactic sugar," which is a more convenient/appealing but functionally equivalent way to express something.
You can use either CAST or the :: operator with Postgres, as they are interchangeable.
I recommend using CAST.
Generally, the standard method of doing things is more beneficial to know for the long-term because that knowledge will transfer when you use a different SQL database.
Filling NULL Values
Sometimes we want to change NULL to something else, either because NULL's properties are confusing/inconvenient or because we want to fill it with a different value.
For example, suppose our app "Yulp" want to fill the cuisine_type with the string "Other" instead of NULL.
SELECT
name,
cuisine_type,
CASE
WHEN cuisine_type IS NOT NULL THEN cuisine_type
ELSE 'Other'
END AS cuisine_type_filled
FROM restaurants
WHERE delivery_fee_usd IS NOT NULL;
| name VARCHAR | cuisine_type VARCHAR | cuisine_type_filled VARCHAR |
|---|---|---|
Harmonious Shift | NULL | Other |
Outlying Centre | French | French |
Gently Accurate Homeownership | Taiwanese | Taiwanese |
Knowing Geography | NULL | Other |
Foolish Chapter | Greek | Greek |
Stale Spelt | Spanish | Spanish |
Diligently Grateful Pecan | Italian | Italian |
Worldly Menu | Vietnamese | Vietnamese |
Scientific Standardization | NULL | Other |
Precious Art | NULL | Other |
Coalesce
There is a nice little shortcut for CASE WHEN x IS NOT NULL THEN x ELSE 0 END.
You can call the function coalesce(x, 0) instead!
SELECT
name,
cuisine_type,
coalesce(cuisine_type, 'Other') AS cuisine_type_filled
FROM restaurants
WHERE delivery_fee_usd IS NOT NULL;
| name VARCHAR | cuisine_type VARCHAR | cuisine_type_filled VARCHAR |
|---|---|---|
Harmonious Shift | NULL | Other |
Outlying Centre | French | French |
Gently Accurate Homeownership | Taiwanese | Taiwanese |
Knowing Geography | NULL | Other |
Foolish Chapter | Greek | Greek |
Stale Spelt | Spanish | Spanish |
Diligently Grateful Pecan | Italian | Italian |
Worldly Menu | Vietnamese | Vietnamese |
Scientific Standardization | NULL | Other |
Precious Art | NULL | Other |