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!