Документация FirebirdДокументация по FirebirdNULL в СУБД Firebird → NULL в выражениях
Firebird home Firebird home Пред.: Что такое NULL?Начало: Документация FirebirdУровень выше: NULL в СУБД FirebirdСлед.: Обработка NULL в UDF

NULL в выражениях

Выражения, возвращающие NULL
NULL в логических выражениях
Больше логики (или нет)
NULL в агрегатных функциях

Как многие из нас узнали, к своему огорчению, NULL - заразен: используйте его в числовых, строковых выражениях или в выражениях, содержащих дату/время, и в результате вы всегда получите NULL; используйте его в логических (булевых) выражениях, и результат будет зависеть от типа опрерации и других вовлеченных значений.

Пожалуйста обратите внимание, что в СУБД Firebird версий до 2.0 чаще всего недопустимо прямое использование константы NULL в операциях и сравнениях. Если вы видите 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 NULL Если A незвестно, то 6 + A также неизвестно.
'Home ' || 'sweet ' || A NULL Если A неизвестно, 'Home sweet ' || A - неизвестно.
MyField = A NULL Если A неизвестно, вы не можете сказать, имеет ли MyField то же самое значение...
MyField <> A NULL ...но вы так же не можете сказать, имеет ли MyField отличающееся значение!
A = B NULL Если A и B незивестны, невозможно знать равны ли они.
not (A) NULL Если A неизвестно, инвертированное значение также неизвестно.

NULL в логических выражениях

Мы уже рассмотрели, что 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) NULL «A or false» всегда имеет то же значение, что и A, которое неизвестно.
A or (true) true «A or true» всегда true - содержимое A не важно.
A or A NULL «A or A» всегда равно A, которое является NULL.
A and (false) false «A and false» всегда false - содержимое A не важно.
A and (true) NULL «A and true» всегда имеет то же значение, что и A, которое неизвестно.
A and A NULL «A and A» всегда равно A, которое является NULL.

Все эти результаты находятся в соответствии с булевой логикой. Факт состоит в том, что в порядке вычисления «X or true» и «X and false» вам просто нет необходимости знать значение X, что так же базируется на известной особенности, которую мы знаем в различных языках программирования под названием «сокращенное (ускоренное) вычисление булевых выражений».

Больше логики (или нет)

Полученные выше результаты сокращенного вычисления могут привести вас к следующим идеям:

  • 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)

Это сделано, чтобы быть последовательными.

NULL в агрегатных функциях

В агрегатных функциях, таких как COUNT, SUM, AVG, MAX и MIN, NULL обрабатывается отличным образом: для вычисления результата принимаются в рассмотрение только значения полей, не содержащие NULL. То есть, если у вас есть такая таблица:

MyTable

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, если использован пустой набор данных, что противоречит общей логике.

Пред.: Что такое NULL?Начало: Документация FirebirdУровень выше: NULL в СУБД FirebirdСлед.: Обработка NULL в UDF
Документация FirebirdДокументация по FirebirdNULL в СУБД Firebird → NULL в выражениях