Шрифт:
Следующий оператор будет отыскивать список всех служащих, кто имеет, по крайней мере, одно изменение оклада в течение года после приема на работу:
SELECT E.EMP_NO, E.FULL_NAME, E.HIRE_DATE
FROM EMPLOYEE E
WHERE E.HIRE_DATE + 365 > SOME (
SELECT SH.CHANGE_DATE FROM SALARY_HISTORY SH
WHERE SH.EMP_NO = E.EMP_NO);
Обратите внимание на использование алиасов таблиц в последних двух примерах, что уменьшает двусмысленность в соответствующих именах столбцов двух таблиц. Firebird весьма требователен к использованию алиасов таблиц в запросах к нескольким таблицам. Алиасы таблиц обсуждаются в главе 22.
Обсуждение NULL
NULL может оказаться довольно сложным для людей, ранее работавших с настольными базами данных, которые просто использовали NULL для хранения "нулевых значений": пустая строка, ноль для чисел, ложь для логических столбцов и т.д. В SQL любой элемент данных в столбце, допускающем пустое значение (то есть в столбце, не имеющем ограничения NOT NULL), будет хранить элемент NULL, если ему не было присвоено никакого значения в операторе DML или в значении по умолчанию для столбца.
Значения по умолчанию для всех столбцов в Firebird допускают пустые значения. Если ваша база данных не была сознательно спроектирована для предотвращения хранения значений NULL, ваши выражения должны быть готовы встретить пустое значение.
NULL в выражениях
NULL не является значением, следовательно, он не может быть "равным" какому-либо значению. Например, воз такой предикат
WHERE (COL1 = NULL)
вернет ошибку, потому что оператор равенства не является действительным для NULL, NULL является состоянием, и правильным предикатом проверки на NULL будет IS NULL. Скорректированный предикат для предыдущего ошибочного тестирования будет иметь вид:
WHERE (COL1 IS NULL)
Вы также можете выполнять проверку на непустое значение:
WHERE (COL1 IS NOT NULL)
Два NULL не равны один другому. При конструировании выражений помните о тех случаях, когда предикат будет сведен к виду:
WHERE <NULL result> = <NULL result>
Здесь результатом всегда будет ложь при сравнении двух NULL. Выражение типа
WHERE COL1 > NULL
будет ошибочным, потому что арифметический оператор недопустим для NULL.
NULL в вычислениях
В выражении пустой операнд даст результат вычисления NULL. Например, следующий оператор
UPDATE TABLEA
SET COL4 = COL4 + C0L5;
присвоит столбцу COL4 значение NULL, если значением COL5 является NULL.
В агрегатном (обобщающем) выражении, использующем операторы типа SUMO, AVG или COUNT (<ИМЯ столбца>), строки, содержащие NULL В соответствующем столбце, будут проигнорированы, AVG сформирует числитель, суммируя непустые значения, и знаменатель, подсчитывая строки, содержащие непустые значения.
Понимание истинности и ложности
Семантически, если предикат возвращает "неопределенность", это не является ни истиной, ни ложью. В SQL при этом утверждения разрешаются только в виде "истина" или "ложь" - утверждение, которое не вычисляется как "истина", рассматривается как "ложь".
Условие IF, неявно присутствующее в предикатах поиска, может вызвать у вас галлюцинацию, когда NOT используется во вложенном условии:
NOT <условие, дающее ложь> дает TRUE
в то время как
NOT <условие, дающее NULL> дает NULL
Чтобы получить пример, когда наши предположения могут оказаться ошибочными, рассмотрим следующее:
WHERE
NOT (COLUMNA = COLUMNB)
Если оба столбца COLUMNA и COLUMNB имеют значения и не равны, вычисление внутреннего предиката (того, что заключен в скобки) даст "ложь". Утверждение NOT (FALSE) вернет истину - противоположность ложного значения.
Однако если любой из столбцов является NULL, внутренний предикат даст NULL, имеющий семантическое значение "неопределенный" ("непроверенный", "неопознаваемый"). Окончательное утверждение будет NOT (NULL), а результатом станет NULL. Обратите также внимание, что NOT (NULL) не является тем же самым, что и IS NOT NULL- чисто бинарный предикат, который никогда не вернет "неопределенное значение".
! ! !
ВНИМАНИЕ! Этот урок заключается в том, что нужно быть внимательным при работе с логикой SQL и всегда жестко проверять ваши выражения. Учитывайте условия NULL, если вы можете это сделать, полностью исключайте утверждения NOT во вложенных предикатах.
. ! .
NULL и внешние функции (UDF)
NULL не может передавать в виде входа или выхода функции в большинстве библиотек внешних функций, потому что они следуют соглашению InterBase о передаче аргументов по ссылке или по значению. Большинство доступных библиотек UDF используют это соглашение InterBase.