| Firebird Documentation Index → NULL в СУБД Firebird → Взаимодействие с NULL |
![]() |
Этот раздел содержит некоторые практические советы и примеры,
которые могут быть использованы вами в вашей повседневной работе с
NULL.
Достаточно часто вам нет необходимости принимать специальные меры
для полей или переменных, которые могут быть NULL.
Например, если вы делаете так:
select * from Customers where Town = 'Ralston'
очевидно, что вы не хотите видеть клиентов, город которых не указан. Аналогично:
if (Age >= 18) then CanVote = 'Yes'
не будут включены люди с неизвестным возрастом, что так же верно и безопасно. Но:
if (Age >= 18) then CanVote = 'Yes'; else CanVote = 'No';
выглядит менее обоснованным: если вы не знаете возраст человека, вы не можете явно лишить его права голоса. Хуже того:
if (Age < 18) then CanVote = 'No'; else CanVote = 'Yes';
не принесет ожидаемый результат, как и в предыдущем случае. Если
кто-то с возрастом NULL имеет реальный возраст до
18, вы предоставите несовершеннолетнему право голоса!
Правильным подходом является явная проверка на
NULL:
if (Age is null) then CanVote = 'Unsure'; else if (Age >= 18) then CanVote = 'Yes'; else CanVote = 'No';Замечание
elseвсегда ссылается на последнийifв этом же блоке. Но чаще всего лучше предотвращать путаницу, помещая ключевые словаbegin...endвокруг группы строк. Я не сделал этого здесь, чтобы сократить количество строк. И поэтому я был вынужден добавить это примечание. ;-)
Иногда вы хотите определить, являются ли значения двух полей или
двух переменных одинаковыми, и вы будете считать их равными, если они
оба NULL. Правильной проверкой для этого является
следующая:
if (A = B or A is null and B is null) then...
или, если вы хотите убрать возможное недопонимание:
if ((A = B) or (A is null and B is null)) then...
Предупреждение. Если только одна из величин A и B является
NULL, тестовое выражение станет
NULL, а не false! Это нормально для оператора
if, и мы даже можем добавить предложение
else, которое будет выполнено, если A и B не равны
(включая случай, когда одна из величин NULL, а
другая - нет):
if (A = B or A is null and B is null) then ...код для выполнения, если A равно B... else ...код для выполнения, если A и B различаются...
Однако откажитесь от идеи инвертирования выражения и использования его как проверки на неэквивалентность (как я это однажды сделал):
/* Не делайте так! */ if (not(A = B or A is null and B is null)) then ...код для выполнения, если A отличается от B...
Приведенный выше код работает корректно, если оба A и B являются
NULL или оба не являются NULL.
Но в нем не выполняется предложение then, если только
одна из частей (A или B) является NULL.
Если вы хотите выполнять что-либо, когда A и B отличаются, вы
должны либо использовать корректное выражение, приведенное выше, и
поместить пустой оператор в предложение then, или
использовать это более длинное выражение для проверки:
/* Это корректный тест на неэквивалентность: */
if (A <> B
or A is null and B is not null
or A is not null and B is null) then...
В триггерах часто бывает полезным знать, что значение
определенного поля изменилось (включая переход от
NULL к не-NULL значению и
наоборот) или осталось тем же самым. Это не что иное, как особый
случай использования проверки на (не)эквивалентность значений двух
полей. Просто вместо A и B используйте New.ИмяПоля и
Old.ИмяПоля:
if (New.Job = Old.Job or New.Job is null and Old.Job is null) then ...поле Job осталось тем же... else ...поле Job изменилось...
В Firebird 1.5 есть функция, которая может конвертировать
NULL во что-то еще. Это позволит вам выполнять
преобразование «на лету» и использовать результат в
последующей обработке без необходимости использования конструкции
«if (MyExpression is null) then».
Функция называется COALESCE, и вы можете вызвать
ее так:
COALESCE(Expr1, Expr2, Expr3, ...)
COALESCE возвращает первое
не-NULL выражение из списка аргументов. Если все
выражения являются NULL, она вернет
NULL.
Вот как вы можете сконструировать полное имя человека с помощью
COALESCE из первого, среднего и последнего имени,
предполагая, что среднее имя может иметь значение
NULL:
select FirstName
|| coalesce(' ' || MiddleName, '')
|| ' ' || Lastname
from Persons
Или для создания наиболее информативного имени, насколько это
возможно, из таблицы, которая содержит псевдонимы, и в предположении,
что и псевдоним и первое имя могут быть
NULL:
select coalesce (Nickname, FirstName, 'Mr./Mrs.')
|| ' ' || Lastname
from OtherPersons
COALESCE поможет вам только в тех
ситуациях, когда NULL можно трактовать одинаково,
как некоторое допустимое значение для типа данных. Если для
NULL необходима специальная обработка, как в
примере с «правом голоса», показанном ранее, вы можете
использовать только выражение «if (MyExpression is
null) then».
В СУБД Firebird 1.0 не существует функции
COALESCE. Однако, вы можете использовать четыре
UDF, которые предоставляют бОльшую часть функциональности функции
COALESCE. Эти UDF расположены в библиотеке
fbudf и называются
iNVL для целочисленных
аргументво
i64NVL для агрументов типа
bigint
dNVL для агрументов типа double
precision
sNVL для строк
Функции *NVL получают два аргумента. По
аналогии с COALESCE, они возвращают первый
аргумент, если он не является NULL; в противном
случае они возвращают второй аргумент. Пожалуйста, обратите внимание,
что это библиотека для Firebird 1.0 fbudf - и поэтому функции
*NVL доступны только для Windows.
| Firebird Documentation Index → NULL в СУБД Firebird → Взаимодействие с NULL |