Шрифт:
Интервал:
Закладка:
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.
Сервер Firebird способен передавать аргументы в UDF по дескриптору. Это механизм, который стандартизует аргументы типов данных Firebird, делая возможным передачу NULL в качестве аргумента кода включающего языка, хотя и не предоставляя возможности получать NULL В качестве возвращаемого значения. Функции в библиотеке fbudf (в каталоге /UDF инсталляции сервера) используют дескрипторы.
Установка значения в NULL
Элемент данных может быть сделан NULL только в столбце, для которого не указано ограничение NOT NULL (СМ. разд. "Ограничение NOT NULL" главы 16).
В операторе UPDATE символом назначения является "=":
UPDATE FOO SET COL3 = NULL
WHERE COL2 = 4;
В операторе INSERT передавайте ключевое слово NULL на месте значения:
INSERT INTO FOO (COL1, COL2, COL3)
VALUES (1, 2, NULL);
для столбца.
! ! !
ПРИМЕЧАНИЕ. В этом случае NULL перекрывает любое значение по умолчанию
. ! .
Другой способ помещения NULL С помощью оператора INSERT - опустить имя столбца, допускающего пустое значение, во входном списке. Например, следующий оператор будет иметь тот же эффект, что и предыдущий, если значение по умолчанию не определено для столбца COL3:
INSERT INTO FOO (COL1, COL2)
VALUES (1, 2);
В PSQL (языке хранимых процедур) используйте символ "=" в качестве оператора присваивания при назначении переменной NULL, используйте is [NOT] NULL в предикате проверки IF:
. . .
DECLARE VARIABLE foobar integer;
. . .
IF (COL1 IS NOT NULL) THEN
FOOBAR = NULL;
Использование выражений
Вычисляемые столбцы
Полезной возможностью SQL является способность генерировать во время выполнения выходные поля с использованием выражений. Firebird поддерживает два вида вычисляемого вывода: поля, создаваемые в операторах DML, и столбцы, которые с помощью DDL были определены в таблице с использованием ключевых слов COMOTED BY как контекстные выражения. Обычно такие поля получаются из хранимых данных, хотя и не обязательно. Они могут быть константами или, в общем виде, контекстными переменными или значениями, получаемыми из контекстных переменных.
Поля, создаваемые в операторахКогда выходной столбец создается с использованием выражения, он называется вычисляемым выходным столбцом. Выходное значение всегда используется только для чтения, потому что оно не является хранимым значением. Любое выражение, которое выполняет сравнение, вычисление или преобразование и возвращает в качестве результата единственное значение, может включать в себя и такие столбцы.
Такое часто происходит, когда выражение использует более одной "формулы" для получения результата. В одном из наших ранних примеров функция (EXTRACT()) и операция (конкатенация) были использованы для получения строки BIRTHDAY, которая была выходной в списке. Такие сложные выражения вовсе не являются редкими.
Алиасы получаемых полей и столбцовВыражения, вывод подзапросов и константы могут быть использованы в Firebird для передачи получаемых, или "искусственных" полей, в выходные наборы. Для предоставления возможности назначать имена во время выполнения Firebird поддерживает стандарт SQL назначения алиасов столбцам, что позволяет выводить любые столбцы с алиасами из одного или более символов.
Например, следующий оператор
SELECT COL_ID, COLA || ',' ||COLB AS comput col
FROM TABLEA;
возвращает столбец с именем comput_col, являющийся конкатенацией значений двух столбцов, разделенных запятыми.
! ! !
ВНИМАНИЕ! Когда два столбца соединяются подобным образом в любом выражении, выходное поле будет NULL, если любой из столбцов является NULL. Это также является стандартным поведением SQL.
. ! .
В следующем примере используется скалярный подзапрос к другой таблице для создания выходного поля времени выполнения:
SELECT COL_ID,
COLA,
COLB,
(SELECT SOMECOL FROM TABLEB
WHERE UNIQUE_ID = '99') AS B_SOMECOL
FROM TABLEA
Скалярный (под)запрос - это тот, который возвращает значение одного столбца из одной строки. Подзапросы обсуждаются в главе 22.
Firebird позволяет стандарту слегка расслабиться в отношении ключевого слова AS - оно необязательно. Опускать его не рекомендуется, потому что это может усложнить поиск алиаса столбца в исходном коде.
Другая часть стандарта требует, чтобы вычисляемые столбцы или получаемые из оператора подзапроса были явно поименованы с помощью алиаса. Текущая версия сервера Firebird позволяет вам опускать имя алиаса для вычисляемых столбцов или столбцов, полученных из подзапроса. Для примера следующий запрос
SELECT CAST(CURRENT_DATE as VARCHAR(10)) || '-' || REGISTRATION
FROM AIRCRAFT;
генерирует такой вывод:
<пробельная титульная строка>
===============
2003- 01-01-GORILLA
2004- 02-28-KANGAROO
. . .
Одни рассматривают это как ошибку, другие - как особенность. Для администратора базы данных удобнее быстро создать запрос, не беспокоясь о деталях. Это строго не рекомендуется использовать как "особенность" в приложениях. Выходные столбцы без имени слишком часто приводят к ошибкам и двусмысленностям в клиентских интерфейсах. Те же самые сложности могут появиться в интерфейсах приложений, если вы используете один и тот же алиас более одного раза в одном выходе.
Константы и переменные в качестве вывода времени выполненияСуществует возможность "создавать" выходной столбец в операторе SELECT, используя выражение, в которое включены не столбцы, а константы или контекстные переменные и алиасы. В следующем тривиальном примере запрос добавляет к каждой строке столбец, содержащий константное значение 'This is just a demo':
SELECT
LAST_NAME,
FIRST_NAME,
'This is just a demo' AS DEMO_STRING
FROM MEMBERSHIP;
Тривиальность, как она проявляется в этом примере, может быть удобным способом настройки вывода, особенно при использовании в выражении CASE.
Использование контекстных переменныхFirebird имеет набор переменных, предоставляющих мгновенный снимок значений сервера. Как вы уже видели, многие из этих значений могут быть использованы в выражениях, выполняющих вычисления. Они также могут быть использованы в выражениях, сохраняющих их в столбцах базы данных, или в спецификациях COMPUTED BY (см. разд. "Объявление столбцов COMPUTED BY").
Контекстные переменные также могут быть использованы в выражениях выходного столбца для передачи серверного значения непосредственно клиенту или модулю PSQL. Например:
SELECT
LOG_ID,
L0G_DATE,
. . .
CURRENT_DATE AS BASE_DATE,
СURRENT_TRANSACTION AS BASE_TRANSACTI0N,
. . .
FROM LOG
WHERE . . .
Подробный список доступных переменных и примеры их использования см. в разд. "Контекстные переменные" главы 8.
Выражения, использующие CASE() и дружественные функцииFirebird предоставляет из стандарта SQL-99 синтаксис выражения CASE и двух его "сокращенных" производных функций - COALESCE() и NULLIF(). Выражение CASE() может быть использовано для вывода константного значения, условно определенного во время выполнения в соответствии со значением указанного столбца в текущей строке запрашиваемой таблицы.
CASE()Функция CASE() позволяет сделать вывод для столбца зависимым от результата вычисления группы взаимоисключающих условий.
ДоступностьDSQL, PSQL, ISQL, ESQL, Firebird 1.5 и выше. Любая платформа.
СинтаксисCASE {<значение 1> | <пустое-предложение>}
WHEN {{NULL | <значение 2>} | <предикат-поиска> }
- Delphi. Учимся на примерах - Сергей Парижский - Программирование
- Сделай видеоигру один и не свихнись - Слава Грис - Программирование / Руководства
- Психбольница в руках пациентов - Алан Купер - Программирование