Firebird Documentation Index → NULL в СУБД Firebird → NULL в выражениях |
Как многие из нас узнали, к своему огорчению,
NULL
- заразен: используйте его в числовых, строковых
выражениях или в выражениях, содержащих дату/время, и в результате вы
всегда получите NULL
; используйте его в логических
(булевых) выражениях, и результат будет зависеть от типа опрерации и
других вовлеченных значений.
Пожалуйста обратите внимание, что в СУБД Firebird версий до 2.0 чаще
всего недопустимо прямое использование константы NULL
в операциях и сравнениях. Если вы видите NULL
в
приведенных ниже выражениях, понимайте это как «значение поля,
переменной или другого выражения, результат вычисления которого есть
NULL
».
Выражения в этом списке всегда возвратят
NULL
:
1 + 2 + 3 +
NULL
'Home ' || 'sweet ' ||
NULL
MyField =
NULL
MyField <>
NULL
NULL
=
NULL
not (
NULL
)
Если вам трудно понять, почему, вспомните, что
NULL
- значит «неизвестно». Также
давайте взглянем на следующую таблицу, где приведено объяснение каждого
случая. В таблице мы не пишем NULL
в выражении (как
уже упоминалось, часто это недопустимо); вместо этого мы используем две
сущности - A и B - которые обе являются NULL
. A и B
могут быть значениями полей, переменных или целых выражений со своими
собственными правилами - но если только они являются
NULL
, они ведут себя одинаково в приведенных
выражениях.
Таблица 1. Операции с NULL
-сущностями A и B
Если A и B являются
NULL , то:
|
Получаем: | Потому что: |
---|---|---|
1 + 2 + 3 + A |
|
Если A незвестно, то 6 + A также неизвестно. |
'Home ' || 'sweet ' || A |
|
Если A неизвестно, 'Home sweet ' || A - неизвестно. |
MyField = A |
|
Если A неизвестно, вы не можете сказать, имеет ли MyField то же самое значение... |
MyField <> A |
|
...но вы так же не можете сказать, имеет ли MyField отличающееся значение! |
A = B |
|
Если A и B незивестны, невозможно знать равны ли они. |
not (A) |
|
Если A неизвестно, инвертированное значение также неизвестно. |
Мы уже рассмотрели, что
not(
дает в результате
NULL
)NULL
. Для операторов and
(логическое И
) и or
(логическое
ИЛИ
) взаимодействие несколько сложнее:
NULL
or
false
=
NULL
NULL
or
true
=
true
NULL
or
NULL
=
NULL
NULL
and
false
=
false
NULL
and
true
=
NULL
NULL
and
NULL
=
NULL
В СУБД Firebird не существует логического (булева) типа данных,
тем не менее существуют константы true
(истина) и
false
(ложь). В левой колонке таблицы с
объяснениями, которую вы видите ниже, (true)
и
(false)
представляют собой вложенные выражения,
возвращающие
true
/false
.
Таблица 2. Логические (булевые) операции с
NULL
-сущностью A
Если A является NULL ,
то:
|
Получаем: | Потому что: |
---|---|---|
A or (false) |
|
«A or
» всегда имеет то же
значение, что и A, которое неизвестно.
|
A or (true) |
|
«A or
» всегда
true - содержимое A не важно.
|
A or A |
|
«A or A » всегда равно A,
которое является NULL .
|
A and (false) |
|
«A and
» всегда
false - содержимое A не важно.
|
A and (true) |
|
«A and
» всегда имеет то же
значение, что и A, которое неизвестно.
|
A and A |
|
«A and A » всегда равно A,
которое является NULL .
|
Все эти результаты находятся в соответствии с булевой логикой.
Факт состоит в том, что в порядке вычисления «X or
» и «true
X and
» вам просто нет
необходимости знать значение X, что так же
базируется на известной особенности, которую мы знаем в различных языках
программирования под названием «сокращенное (ускоренное)
вычисление булевых выражений».
false
Полученные выше результаты сокращенного вычисления могут привести вас к следующим идеям:
0 умноженное на x
равно 0 для любого
x
. Поэтому, даже если значение
x
неизвестно, 0 * x
равно 0.
(Обратите внимание: это верно только если x
имеет
числовой тип данных, а не NaN
или
бесконечность.)
Пустая строка располагается лексикографически перед любой
другой строкой. Поэтому, S >= ''
равно true не
зависимо от значения S.
Каждое значение равно самому себе, независимо от того,
известно оно или нет. Таким образом, хотя A = B
обоснованно вернет NULL
, если A и B являются
различными NULL
-сущностями, A =
A
должно всегда возвращать true
, даже
если A является NULL
.
Как это реализовано в СУБД Firebird? Что ж, мне очень жаль, но я
должен сообщить вам, что, несмотря на такую неотразимую логику и
аналогию с результатами булевых операций, описанных выше, следующие
выражения всегда дают в итоге NULL
:
0 * NULL
NULL
>= ''
'' <=
NULL
A = A
(если A является полем или переменной
со значением NULL
)
Это сделано, чтобы быть последовательными.
В агрегатных функциях, таких как COUNT
,
SUM
, AVG
,
MAX
и MIN
,
NULL
обрабатывается отличным образом: для
вычисления результата принимаются в рассмотрение только значения полей,
не содержащие NULL
. То есть, если у вас есть такая
таблица:
ID | Name | Amount |
---|---|---|
1 | John | 37 |
2 | Jack | <NULL >
|
3 | Joe | 5 |
4 | Josh | 12 |
5 | Jay | <NULL >
|
...выражение select sum(Amount) from
MyTable
вернет 54, что получается из 37 + 5 + 12. Если бы
все пять значений полей были просуммированы, в результате должен был бы
получиться NULL
. Для AVG
суммируются значения полей, не содержащие NULL
, а
сумма делится на количество таких значений.
Есть одно исключение из этого правила:
COUNT(*)
вернет количество всех записей, даже тех
записей, значения всех полей которых являются NULL
.
Но COUNT
(ИмяПоля
) ведет себя
как и остальные агрегатные функции, то есть считает записи, в которых
значение указанного поля не является NULL
.
Еще одно свойство достойно упоминания.
COUNT(*)
и
COUNT(
никогда не
вернут ИмяПоля
)NULL
: если нет записей в наборе данных, обе
функции вернут 0. Также,
COUNT(
вернет 0,
если все значения поля ИмяПоля
)ИмяПоля
в наборе данных
являются NULL
. Другие агрегатные функции вернут
NULL
в таком случае. Имейте в виду, что даже
SUM
вернет NULL
, если
использован пустой набор данных, что противоречит общей логике.
Firebird Documentation Index → NULL в СУБД Firebird → NULL в выражениях |