NULL in operations
<< NULL support in Firebird SQL | Firebird Null Guide | Internal functions and directives >>
NULL
in operations
As many of us have found out to our chagrin, NULL
is contagious: use it in a numerical, string or date/time operation, and the result will invariably be NULL
. With Boolean operators, the outcome depends on the type of operation and the value of the other operand.
Please remember that in Firebird versions prior to 2.0 it is mostly illegal to use the constant NULL
directly in operations or comparisons. Wherever you see NULL
in the expressions below, read it as "a field, variable or other expression that resolves to NULL
". In Firebird 2 and above this expression may also be a NULL
literal.
Mathematical and string operations
The operations in this list always return NULL
:
1 + 2 + 3 + NULL
5 * NULL - 7
'Home ' || 'sweet ' || NULL
MyField = NULL
MyField <> NULL
NULL = NULL
If you have difficulty understanding why, remember that NULL
means "unknown". You can also look at the following table where per-case explanations are provided. In the table we don't write NULL
in the expressions (as said, this is often illegal); instead, we use two entities A
and B
that are both NULL
. A
and B
may be fields, variables, or even composite subexpressions – as long as they're NULL
, they'll all behave the same in the enclosing expressions.
Table 1. Operations on null entities A and B | ||
If A and B are NULL , then: | Is: | Because: |
---|---|---|
1 + 2 + 3 + A | NULL | If A is unknown, then 6 + A is also unknown. |
5 * A - 7 | NULL | If A is unknown, then 5 * A is also unknown. Subtract 7 and you end up with another unknown. |
'Home ' || 'sweet ' || A | NULL | If A is unknown, 'Home sweet ' || A is unknown. |
MyField = A | NULL | If A is unknown, you can't tell if MyField has the same value... |
MyField <> A | NULL | ...but you also can't tell if MyField has a different value! |
A = B | NULL | With A and B unknown, it's impossible to know if they are equal. |
Here is the complete list of math and string operators that return NULL
if at least one operand is NULL
:
+
,-
,*
,/
, and%
!=
,~=
, and^=
(synonyms of<>
)<
,<=
,>
, and>=
!<
,~<
, and^<
(low-precedence synonyms of>=
)!>
,~>
, and^>
(low-precedence synonyms of<=
)||
[NOT] BETWEEN
[NOT] STARTING WITH
[NOT] LIKE
[NOT] CONTAINING
The explanations all follow the same pattern: if A
is unknown, you can't tell if it's greater than B
; if string S1
is unknown, you can't tell if it contains S2
; etcetera.
Using LIKE
with a NULL
escape character would crash the server in Firebird versions up to and including 1.5. This bug was fixed in v. 1.5.1. From that version onward, such a statement will yield an empty result set.
Boolean operations
All the operators examined so far return NULL
if any operand is NULL
. With Boolean operators, things are a bit more complex:
not NULL = NULL
NULL or false = NULL
NULL or true = true
NULL or NULL = NULL
NULL and false = false
NULL and true = NULL
NULL and NULL = NULL
In reality, Firebird SQL doesn't have a Boolean data type; nor are true
and false
existing constants. In the leftmost column of the explanatory table below, true
and false
represent expressions (fields, variables, composites...) that evaluate to true
/false
.
Table 2. Boolean operations on null entity A | ||
If A is NULL , then: | Is: | Because: |
---|---|---|
not A | NULL | If A is unknown, its inverse is also unknown. |
A or false | NULL | A or false always has the same value as A – which is unknown. |
A or true | true | A or true is always true – A 's value doesn't matter. |
A or A | NULL | A or A always equals A – which is NULL . |
A and false | false | A and false is always false – A 's value doesn't matter. |
A and true | NULL | A and true always has the same value as A – which is unknown. |
A and A | NULL | A and A always equals A – which is NULL . |
All these results are in accordance with Boolean logic. The fact that you don't need to know X
's value to compute X or true
and X and false
is also the basis of a feature found in various programming languages: short-circuit Boolean evaluation.
The above results can be generalised as follows for expressions with one type of binary Boolean operator (and | or) and any number of operands:
Disjunctions ("A or B or C or D or ..."
)
- If at least one operand is
true
, the result istrue
. - Else, if at least one operand is
NULL
, the result isNULL
. - Else (i.e. if all operands are
false
) the result isfalse
.
Conjunctions ("A and B and C and D and ..."
)
- If at least one operand is
false
, the result isfalse
. - Else, if at least one operand is
NULL
, the result isNULL
. - Else (i.e. if all operands are
true
) the result istrue
.
Or, shorter:
TRUE
beatsNULL
in a disjunction (OR
-operation);FALSE
beatsNULL
in a conjunction (AND
-operation);- In all other cases,
NULL
wins.
If you have trouble remembering which constant rules which operation, look at the second letter: tRue prevails with oR —fAlse with And.
More logic (or not)
The short-circuit results obtained above may lead you to the following ideas:
0
timesx
equals0
for everyx
. Hence, even ifx
's value is unknown,0 * x
is0
. (Note: this only holds ifx
's datatype only contains numbers, notNaN
or infinities.)- The empty string is ordered lexicographically before every other string. Therefore,
S >= ''
istrue
whatever the value ofS
. - Every value equals itself, whether it's unknown or not. So, although
A = B
justifiably returnsNULL
ifA
andB
are differentNULL
entities,A = A
should always returntrue
, even ifA
isNULL
. The same goes forA <= A
andA >= A
.
A <> A
should always be false
, as well as A < A
and A > A
.
- Every string contains itself, starts with itself and is like itself. So,
S CONTAINING S
,S STARTING WITH S
andS LIKE S
should always returntrue
.
How is this reflected in Firebird SQL? Well, I'm sorry I have to inform you that despite this compelling logic – and the analogy with the Boolean results discussed above – the following expressions all resolve to NULL
:
0 * NULL
NULL >=
and<= NULL
A = A
,A <= A
andA >= A
A <> A
,A < A
andA > A
S CONTAINING S
,S STARTING WITH S
andS LIKE S
So much for consistency.
See also:
Comparison operators
back to top of page
<< NULL support in Firebird SQL | Firebird Null Guide | Internal functions and directives >>