| 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
» и «trueX 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 в выражениях |