6.4.3. Expressions involving NULL
In SQL, NULL
is not a value. It is a condition, or state, of a data item, in which its value is unknown. Because it is unknown, NULL
cannot behave like a value. When you try to perform arithmetic on NULL
, or involve it with values in other expressions, the result of the operation will almost always be NULL
. It is not zero or blank or an “empty string” and it does not behave like any of these values.
Below are some examples of the types of surprises you will get if you try to perform calculations and comparisons with NULL
.
The following expressions all return NULL
:
1 + 2 + 3 + `NULL`
not (NULL)
'Home ' || 'sweet ' || NULL
You might have expected 6 from the first expression and “Home sweet
” from the third, but as we just said, NULL
is not like the number 0 or an empty string — it’s far more destructive!
The following expression:
FirstName || ' ' || LastName
will return NULL
if either FirstName
or LastName
is NULL
. Otherwise it will nicely concatenate the two names with a space in between — even if any one of the variables is an empty string.
Think of |
Now let’s examine some PSQL (Procedural SQL) examples with if
-constructs:
Equals (‘
=
’)if (a = b) then
MyVariable = 'Equal';
else
MyVariable = 'Not equal';
After executing this code,
MyVariable
will be'Not equal'
if botha
andb
areNULL
. The reason is thata = b
yieldsNULL
if at least one of them isNULL
. If the test expression of an “if
” statement isNULL
, it behaves likefalse
: the ‘then
’ block is skipped, and the ‘else
’ block executed.Although the expression may behave like
false
in this case, it’s stillNULL
. If you try to invert it usingnot()
, what you get is anotherNULL
— not “true
”.Not equals (‘
<>
’)if (a <> b) then
MyVariable = 'Not equal';
else
MyVariable = 'Equal';
Here,
MyVariable
will be'Equal'
ifa
isNULL
andb
isn’t, or vice versa. The explanation is analogous to that of the previous example.
The DISTINCT
keyword comes to the rescue!
Firebird 2 and above implement a new use of the DISTINCT
keyword allowing you to perform (in)equality tests that take NULL
into account. The semantics are as follows:
Two expressions are
DISTINCT
if they have different values or if one isNULL
and the other isn’t;They are
NOT DISTINCT
if they have the same value or if they are bothNULL
.
Notice that if neither operand is NULL
, DISTINCT
works exactly like the “<>
” operator, and NOT DISTINCT
like the “=
” operator.
DISTINCT
and NOT DISTINCT
always return true
or false
, never NULL
.
Using DISTINCT
, you can rewrite the first PSQL example as follows:
if (a is not distinct from b) then
MyVariable = 'Equal';
else
MyVariable = 'Not equal';
And the second as:
if (a is distinct from b) then
MyVariable = 'Not equal';
else
MyVariable = 'Equal';
These versions will give you the results that a normal (i.e. not SQL-brainwashed) human being would expect, whether there are NULL
s involved or not.
More about NULL
s
A lot more information about NULL
behaviour can be found in the Firebird Null Guide, at these locations:
https://www.firebirdsql.org/file/documentation/html/en/firebirddocs/nullguide/firebird-null-guide.html (HTML)
https://www.firebirdsql.org/file/documentation/pdf/en/firebirddocs/nullguide/firebird-null-guide.pdf (PDF)