NULL
SQL has a special value called NULL.
It represents nothing, N/A, unknown, invalid, etc.
Let's look at an example.
You're building a restaurant review app called "Yulp", and the restaurants you support are in a table called restaurants.
Have a look at the preview and notice the NULL values.
| column_name | type |
|---|---|
id | INTEGER |
name | VARCHAR |
cuisine_type | VARCHAR |
delivery_fee_usd | NUMERIC |
address | VARCHAR |
Several of these columns have NULL in them.
NULL can take the place of a VARCHAR, NUMERIC, or any data type.
What exactly a NULL means depends on what the engineers were thinking when they put it there.
For this restaurants table, the cuisine_type can be NULL.
This might mean "unknown" because we don't know what kind of cuisine it is.
It could mean "N/A" because the restaurant is so avant-garde that it cannot be categorized.
Why could the address be NULL?
Maybe the restaurant is delivery-only, with no dine-in or pick-up option, and therefore need not present an address.
The delivery fee being NULL might mean the restaurant doesn't do delivery, or maybe that delivery is free.
Arguably, if delivery is free, the delivery fee should just be $0.00.
However, you will often find that data in the real world isn't always intuitive.
Checking for NULL
Let's query all restaurants where the cuisine_type is NULL.
Easy query, right?
SELECT *
FROM restaurants
WHERE cuisine_type = NULL;
| id INTEGER | name VARCHAR | cuisine_type VARCHAR | delivery_fee_usd NUMERIC | address VARCHAR |
|---|---|---|---|---|
| no rows | ||||
We get no rows! What's going on?
A counter-intuitive feature of NULL is that it cannot be compared with any other values, not even itself.
This is because NULL is supposed to represent a value which cannot be determined,
so you wouldn't expect be able to determine whether it equals (or does not equal) some other value.
Imagine if you didn't know how old Alice and Bob are, and then someone asks you if they are the same age (if their ages are equal).
If you represented an unknown age with NULL, and compared Alice's and Bob's ages (compare NULL with NULL),
the result should also be NULL.
If the result were either TRUE (they are the same age) or FALSE (they are not the same age),
it would mean that a certain answer was made, which is impossible in this scenario.
Have a look at these comparisons.
SELECT
NULL > 2 AS "greater_than_2?",
NULL <= 2 AS "less_than_equal_to_2?",
NULL = NULL AS "equal_itself?",
NULL != 'Andy' AS "not_equal_string?";
| greater_than_2? BOOL | less_than_equal_to_2? BOOL | equal_itself? BOOL | not_equal_string? BOOL |
|---|---|---|---|
| NULL | NULL | NULL | NULL |
We might expect these comparisons to evaluate to either TRUE or FALSE.
However, they are all just NULL!
The reason we get 0 rows when using WHERE cuisine_type = NULL is that rows having a NULL result in the WHERE clause get filtered out,
just the same as rows having a FALSE result.
So how can we get rows with NULL values?
SQL has a special operator for this.
SELECT *
FROM restaurants
WHERE cuisine_type IS NULL;
| id INTEGER | name VARCHAR | cuisine_type VARCHAR | delivery_fee_usd NUMERIC | address VARCHAR |
|---|---|---|---|---|
34037 | Harmonious Shift | NULL | 5 | 755 Crist Dam, Bolingbrook |
92740 | Similar Envelope | NULL | NULL | 55109 Isom Streets, Visalia |
40093 | Gross Waistband | NULL | NULL | 2128 Armstrong Drive, Winston-Salem |
56563 | Third Owl | NULL | NULL | 03363 Lane Prairie, Oak Park |
72451 | Knowing Geography | NULL | 9 | NULL |
22625 | Original Durian | NULL | NULL | 968 Benedict Green, Stockton |
9938 | Quick Bibliography | NULL | NULL | 27834 Lorena Point, Highland |
67230 | Scientific Standardization | NULL | 8 | 478 Arthur Port, Victoria |
63483 | Moist Bongo | NULL | NULL | 2225 Glen Walk, Lauderhill |
28676 | Precious Art | NULL | 5 | NULL |
Calculations with NULL
NULL also produces NULL when passed into most functions or math operations.
SELECT
2 + NULL AS null_addition,
2 * NULL AS null_multiplication,
power(2, NULL) AS null_exponentiation,
upper(NULL) AS string_manipulation;
| null_addition INTEGER | null_multiplication INTEGER | null_exponentiation FLOAT | string_manipulation TEXT |
|---|---|---|---|
| NULL | NULL | NULL | NULL |
Double-Quoted Identifiers
Did you notice what I did here?
SELECT NULL = NULL AS "equal_itself?";
| equal_itself? BOOL |
|---|
| NULL |
The alias has quotation marks (double-quotes as opposed to single-quotes). This is because a question mark is part of the alias name. Without it, we get an error!
SELECT NULL = NULL AS equal_itself?;
error: syntax error at or near "?"This is because SQL's rules limit identifiers (the names for tables, columns, aliases, functions, etc.) to specific characters, e.g. they cannot normally contain spaces or certain punctuation marks. However, if you insist on having those special characters, you can wrap that identifier in double-quotes.
SELECT 2 + 2 AS "basic arithmetic problem";
| basic arithmetic problem INTEGER |
|---|
4 |
Remember that single-quotes are for string literals and double-quotes are for identifiers with special characters!