Главная » SQL, Базы данных » СРЕДСТВА поддержки неопределенных значений (NULL) и трехзначной логики в языке SQL

0

Поддержка неопределенных значений (NULL) и трехзначной логики в языке SQL отражает весь широкий спектр подходов, описанных в предыдущих разделах. Так, например, когда в языке SQL условие WHERE применяется к некоторой таблице т, при этом исключаются из рассмотрения все строки таблицы т, для которых указанное в конструкции WHERE выражение принимает значение  false или unk (т.е. не true). Аналогичным образом, когда к результату выполнения некоторой операции группирования, представленному таблицей G, применяется конструкция HAVING, ИЗ дальнейшего рассмотрения исключаются все группы  кортежей таблицы G, для которых указанное в конструкции HAVING выражение принимает значение false или unk (т.е. не true)10. Из этого следует, что мы просто обратили внимание читателя на некоторые средства поддержки трехзначной логики, характерные для языка SQL как такового, а не являющиеся неотъемлемой частью описанного выше подхода, основанного на использовании трехзначной лэгики.

9   Обратите внимание, что для этого не используется неопределенное значение (NULL). В реальном мире никакого понятия неопределенного значения вообще не существует ([19.12]).

10   В языке SQL сгруппированной называется таблица, которая создается в результате выполнения конструкции GROUP BY (возможно, неявной). А после выполнения соответствующего оператора SELECT такая таблица сводится к обычной, "несгруппированной" таблице.

Примечание. Все последствия поддержки неопределенных значений (NULL) В языке SQL оценить очень сложно; фактически, хотя уже было сказано, что в языке  SQL  в целом поддерживается трехзначная логика, истина состоит в том, что в вопросах этой поддержки допущены многочисленные ошибки, как вскоре  будет  показано. Дополнительную информацию можно найти в официальных документах стандарта SQL [4.23] и в учебном издании [4.20].

Типы данных

Как уже было показано в главе 4, в языке SQL предусмотрен встроенный  тип BOOLEAN (он был введен в стандарт в 1999 году, но в настоящее время его поддерживают лишь немногие продукты, если вообще таковые имеются). Предусмотрены обычные логические операторы AND, OR и NOT, и логические выражения могут присутствовать в любом месте, где обычно допускается наличие  скалярных выражений. Но, как указано в данной главе, теперь определены три истинностных значения, а не два (соответствующими литералами являются TRUE, FALSE и UNKNOWN), но несмотря на этот факт, тип BOOLEAN включает только два значения, а не три. Таким образом, неизвестное {unknown) истинностное  значение совершенно неправильно представлено с помощью неопределенного значения NULL! Ниже описаны некоторые следствия из этого факта.

■     Присваивание значения UNKNOWN переменной в типа BOOLEAN фактически равно сильно присваиванию этой переменной неопределенного значения.

■     После такого присваивания операция сравнения в = UNKNOWN не дает в результа те true (или, скорее, TRUE); вместо этого результатом становится неопределенное значение.

■     В действительности, операция сравнения в = UNKNOWN всегда приводит к полу чению неопределенного значения, независимо от значения в! Дело в том, что та кая операция логически эквивалентна операции сравнения "в = NULL" (которая не рассматривается как синтаксически допустимая).

Для того чтобы понять серьезность указанных недостатков, необходимо обратиться к аналогии с числовым типом, в котором для представления нуля использовалось бы неопределенное значение вместо нулевого.

Теперь предположим, что т — нескалярный тип или структурированный тип (и в данном контексте не играет роли, рассматриваются ли структурированные типы как скалярные или нескалярные). Чтобы уточнить описание, предположим, что т представляет собой именно строковый тип, а переменная V является переменной типа т. В таком случае, безусловно, существует логическое различие между самой переменной V, имеющей неопределенное значение, и переменной V, имеющей по меньшей мере один компонент (т.е. поле), который содержит неопределенное значение. Действительно, сама переменная V не обязательно имеет  неопределенное значение", даже если неопределенными являются  все  ее  компоненты!  Тем  не  менее,  по-видимому,  обоснованным  является утверждение (хотя в стандарте нет явных указаний на этот счет), что если значение v не определено, то все компоненты этой переменной также рассматриваются как имеющие неопределенное значение. Поэтому, если значение V не является неопределенным, но эта

11 В действительности, в языке SQL и эта ситуация трактуется неправильно; см. описание конструкции IS [NOT] NULL в подразделе "Логическиевыражения".

переменная содержит по меньшей мере один неопределенный компонент, то в результате сравнения V = V будет получено неопределенное значение и, тем не менее, выражение V IS NULL будет равно FALSE. Но, в общем, можно хотя бы утверждать, что если выражение  ((V  =  V)  is  NOT  TRUE) is  TRUE  равно  TRUE,  то  переменная  vявляется  либо неопределенной, либо содержит неопределенный компонент.

Базовые таблицы

Как описано в разделе 6.6 главы 6, для столбцов в базовых таблицах обычно предусмотрены соответствующие значения, применяемые по умолчанию; они часто определяются (явно или неявно), как неопределенные значения NULL. Более того, столбцы в таблицах всегда разрешают использование неопределенных значений, если условие запрета их использования не будет указано явно (например, в виде фразы NOT NULL).

Из указанного выше следует, что если мы твердо придерживаемся  декларируемых принципов, то действительно обязаны задавать ключевое слово  NOT NULL, явно или неявно, для каждого столбца базовый таблицы в каждом  примере SQL, приведенном выше в данной книге. Но, по меньшей мере, это требование будет соблюдаться во всех примерах SQL начиная с этого момента. Однако следует отметить, что применение ключевого слова NOT NULL неявно подразумевается для любого столбца, указанного в спецификации PRIMARY KEY.

Табличные выражения

Напомним замечание из главы 8 (раздел 8.7) о том, что явная поддержка операции JOIN была введена в стандарт языка SQL в 1992 году. Более того, если перед ключевым словом JOIN указан один из префиксов LEFT, RIGHT или FULL (С необязательным ключевым словом OUTER в каждом случае), рассматриваемое соединение является внешним. Ниже приведено несколько примеров.

S LEFT JOIN SP ON S.S# = SP.S# S LEFT JOIN SP USING ( S# ) S LEFT NATURAL JOIN SP

Три приведенных выражения эквивалентны, но первое приводит к созданию  таблицы с двумя идентичными столбцами s#, а второе и третье — таблицы с одним таким столбцом.

Язык SQL поддерживает также аппроксимацию внешнего объединения, которую называют объединяющим соединением (эта операция была введена в спецификации SQL: 1992, но должна быть удалена в SQL:2003). Однако подробное обсуждение этого вопроса выходит за рамки данной главы.

Логические выражения

Не удивительно то, что в языке SQL логические выражения испытывают  сильное влияние неопределенных значений и трехзначной логики. Остановимся на рассмотрении лишь нескольких наиболее важных частных случаев, которые описаны ниже.

■  Проверка наличия неопределенного значения. В языке SQL предусмотрены два специальных оператора сравнения, IS NULL и IS NOT NULL,  предназначенных для проверки наличия или отсутствия неопределенных значений. Синтаксис использования этих операторов показан ниже.

<row value constructor IS   [  NOT  ]    NULL

Если  в  выражении  <row  value  constructor  с  определением   конструктора значения строки "конструируется" строка со степенью один,  то в языке SQL это выражение рассматривается так, как будто оно  фактически указывает на значение, содержащееся в этой строке, а не на саму строку как таковую; в противном случае это выражение  рассматривается  как  указывающее  на  строку.  Но  в  последнем  случае считается, что строка имеет  неопределенное значение тогда и только тогда, когда каждый  ее  компонент   является  неопределенным,  а  не  имеет  неопределенного значения — тогда и только тогда, когда каждый ее компонент имеет значение, отличное от  неопределенного! Одним следствием этой ошибки является то, что если  r  — строка с двумя компонентами, то выражения r IS NOT NULL и NOT (r IS NULL) не являются эквивалентными; первое из них эквивалентно выражению  cl  is  NOT NULL AND c2 is NOT NULL, а второе — выражению с 1 IS NOT NULL OR c2 IS NOT NULL. Еще одним следствием из указанного  является то, что если строка r одновременно   включает  и   компоненты   с   неопределенными,  и  компоненты  с определенными значениями, то сама строка r, безусловно, не может рассматриваться ни как имеющая неопределенное значение, ни как имеющая определенное значение.

■   Проверка  наличия значений true, false и unknown. Если р — это  заключенное  в круглые  скобки  логическое  выражение  (фактически  в  некоторых  случаях  можно обойтись без круглых скобок, но они никогда не  помешают), то следующие операторы также являются логическими выражениями.

р IS [ NOT ] TRUE р IS [ NOT ] FALSE p IS [ NOT ] UNKNOWN

Значения этих выражений показаны в приведенной ниже таблице истинности.

Обратите внимание на то, что выражения р IS NOT TRUE и NOT p не  являются эквивалентными.

Примечание. Выражение р IS UNKNOWN соответствует описанному выше оператору MAYBE   (р).  Если  считать,  что  в  языке  SQL  для  представления   значения  unk используются неопределенные значения, то данное выражение  эквивалентно также выражению р  IS NULL.

■   Условия EXISTS. Оператор EXISTS языка SQL не является аналогичным  квантору существования в трехзначной логике, поскольку он всегда возвращает значение true или  false,  но  не  unk,  даже  если  unk  —  логически   правильный  ответ.  А именно, этот оператор возвращает false, если таблица, заданная в нем в качестве

фактического параметра, пуста, и true в ином случае (Поэтому он иногда возвращает true, тогда как ипк— логически правильный ответ).  Дополнительная информация на эту тему приведена в [19.6].

■        Условия UNIQUE. Неформально говоря, условия UNIQUE служат для проверки того, что указанная таблица не содержит дубликатов строк (именно так!). Точнее, выражение UNIQUE (< table exp>) возвращает  true,  если таблица, обозначенная с помощью параметра < table exp>, не включает двух разных строк, скажем, rl и r2, таких что операция  сравнения rl = r2 возвращает true; в противном случае данное  выражение возвращает false. Поэтому UNIQUE, как и EXISTS, иногда возвращает true, даже когда ипк — логически правильный ответ.

■     Условия DISTINCT. Условия DISTINCT, вообще говоря, предназначены для про верки того, не являются ли две строки дубликатами друг друга. Обозначим две рас сматриваемые строки как Left и Right; строки Left и Right должны иметь одинаковую степень, скажем, п. Допустим, что i-ми компонентами Left и Right, соответственно, являются Li и Ri (i = 1,   2,   . . .,   п); все компоненты Li и Ri должны быть такими, что операция сравнения Li  = Ri является действительной. В таком случае следующее выражение

Left IS DISTINCT FROM Right

возвращает false, если для всех i либо операция сравнения "Li = Ri"  возвращает true, либо оба значения, Li и Ri, являются неопределенными; в противном случае указанное выражение возвращает true.

Другие скалярные выражения

И снова рассмотрим лишь несколько важных частных случаев, которые описаны ниже.

■     "Литералы". Ключевое слово NULL может иногда использоваться как своего рода литеральное представление неопределенного значения (например, в операторе INSERT), но не во всех контекстах; в стандарте SQL указано, что "ключевое слово NULL … может применяться для обозначения неопределенного значения… в неко торых контекстах, [но] повсеместное использование этого литерала не допускается" [4.23]. В частности, следует отметить, что ключевое слово NULL нельзя применять для обозначения операнда простого оператора сравнения; например, выражение "WHERE   х   =   NULL" является .недопустимым (правильная форма, безусловно,

WHERE X  IS  NULL).

■     COALESCE. Оператор COALESCE — это аналог предложенного автором оператора IF_UNK в языке SQL. Точнее, выражение COALESCE  (x,y,  . . . ,    z) возвращает неопределенное значение, если все его параметры х,   у,   . . .,   z возвращают не определенное значение; в противном случае оно возвращает первый свой операнд, отличный от неопределенного значения.

■     Агрегирующие операторы. Агрегирующие операторы SQL (SUM, AVG и т.д.) не дей ствуют в соответствии с правилами для скалярных операторов, описанными в раз деле 19.2, а вместо этого просто игнорируют все неопределенные значения своих фактических параметров (не считая выражения COUNT (*), в котором неопреде ленные значения рассматриваются так, как если бы они были определенными

значениями). Кроме того, если оказалось, что фактический параметр такого оператора соответствует пустому множеству, то оператор COUNT возвращает нуль, а все остальные операторы — неопределенное значение. (Как было указано в главе 8, такая организация функционирования логически не обоснована, но язык SQL определен именно так.)

■     "Скалярные подзапросы". Если скалярное выражение фактически представляет собой табличное выражение, заключенное в круглые скобки, например, (SELECT

S.CITY    FROM    S    WHERE    S . S#     =     S# (‘ S1 ‘ ) ) ,  TO В  обыЧНЫХ УСЛОВИЯХ ЭТО Табличное выражение должно давать в результате таблицу, содержащую точно один столбец и точно одну строку. Поэтому значением этого скалярного  выражения должно служить единственное скалярное значение,  содержащееся внутри этой таблицы. Но если результатом вычисления данного табличного выражения становится таблица с одним столбцом,  вообще не содержащая строк, то в языке SQL значение скалярного выражения задается как неопределенное.

Ключи

Различные варианты взаимодействия между неопределенными значениями и ключами в языке SQL можно в целом описать, как показано ниже.

■     Потенциальные ключи. Допустим, что с — столбец, который является компонентом некоторого потенциального ключа к некоторой базовой таблицы. Как было отмече но раньше в этом разделе, если к — первичный ключ, то согласно спецификации SQL наличие каких-либо неопределенных значений в столбце с не допускается (иными словами, спецификация SQL требует соблюдения правила целостности сущности). А если к не является первичным ключом, то спецификация SQL до пускает наличие в столбце С любого количества неопределенных значений (но, ра зумеется, при условии, что никакие две разные строки не содержат одинакового

В связи со сказанным, автор предлагает поразмыслить над приведенной ниже немного отредактированной цитатой из [4.20].

"Допустим, что к2 — новое значение для К, которое определенный пользователь пытается ввести с помощью операции INSERT или UPDATE… Эта операция INSERT или UPDATE будет отвергнута, если к2 совпадает с некоторым другим значением К, скажем, kl, которое уже существует в таблице… Но что подразумевается под тем, что два значения, kl и к2, совпадают ? Оказывается, что никакие два из следующих трех утверждений не являются эквивалентными:

1.          kl и к2 являются одинаковыми с точки зрения операции сравнения;

2.          kl и к2 являются одинаковыми с точки зрения обеспечения уникальности потен циальных ключей;

3.          kl и к2 являются одинаковыми с точки зрения устранения дубликатов.

Утверждение 1 определено в соответствии с правилами трехзначной логики, утверждение 2 определено в соответствии с правилами для условия UNIQUE, а утверждение 3 сформулировано в соответствии с определением дубликатов, приведенном в разделе 19.2. В частности, если оба значения, kl и к2, являются неопределенными, то проверка,

выполняемая в соответствии с утверждением 1, приводит к получению unk, с утверждением 2 — false и с утверждением 3 — true".

■   Внешние ключи. Правила, определяющие, что подразумевается под  совпадением данного значения внешнего ключа с соответствующем ему  значением потенциального ключа в присутствии неопределенных  значений, являются весьма сложными.   В   этом  разделе   подробные   сведения   об  этом   не   рассматриваются. Примечание. Наличие неопределенных значений отражено также в определениях ссылочных  действий (CASCADE, SET NULL И Т.Д.), указанных в конструкциях ON DELETE  и  ON  UPDATE.  (Кроме того,  поддерживается  ключевое  слово  SET DEFAULT, имеющее очевидную интерпретацию.) И в этом случае  применяемые правила являются весьма сложными и их описание  выходит  за рамки данной книги; дополнительные сведения приведены в [4.20].

Внедренные операторы SQL

■     Индикаторные переменные. Рассмотрим следующий пример внедренного выраже ния SQL. (Он уже рассматривался в главе 4 при описании однострочного операто ра SELECT.)

EXEC SQL SELECT STATUS, CITY INTO

:RANK, :TOWN FROM S WHERE S# = S# ( :GIVENS# ) ;

Предположим, что для некоторых поставщиков атрибут STATUS может содержать неопределенное  значение.  Тогда  выполнение  приведенного  выше  оператора SELECT завершится неудачей, если в выбранном кортеже атрибут STATUS будет содержать неопределенное значение (в переменную SQLSTATE будет помещен код ошибки 22 002). В общем случае, когда существует вероятность, что выбираемое значение может оказаться  неопределенным, для данного атрибута пользователь должен указать, помимо целевой, еще и индикаторную переменную. Пример определения индикаторной переменной приведен ниже.

EXEC SQL SELECT STATUS, CITY

INTO :RANK INDICATOR :RANKIND, :TOWN FROM S

WHERE S# = S# ( :GIVENS# ) ;

IF RANKIND = -1 THEN /* Значение STATUS было неопределенным */

… ; END IF ;

Если значение, которое нужно выбрать, является неопределенным и для данного атрибута задана индикаторная переменная, то в эту переменную  будет помещено значение -1 (значение, помещаемое в целевую переменную, зависит от реализации).

■     Упорядочение. Для упорядочения строк, полученных в результате вычисления таб личного выражения, в определении курсора используется конструкция ORDER BY. (Безусловно, она может использоваться и при вводе интерактивных запросов.) Возникает вопрос: "Каков относительный порядок двух скалярных значений А и B, если либо А является неопределенным значением, либо в является неопределен ным значением, либо оба они одновременно являются неопределенными значе ниями?". В стандарте языка SQL на этот вопрос даются приведенные ниже ответы.

1.          В процессе упорядочения все неопределенные значения считаются равными одно другому.

2.          В процессе упорядочения все неопределенные значения считаются либо боль шими всех определенных значений, либо меньшими всех определенных значе ний (реальный выбор одной из этих возможностей зависит от конкретной реа лизации).

19.1.     РЕЗЮМЕ

В этой главе обсуждалась проблема отсутствующей информации, а также выбранный в настоящее время (хотя и очень неудачный) подход к ее решению, базирующийся на использовании неопределенных значений и трехзначной логики. Было показано, что неопределенное значение на самом деле значением не является, хотя так и принято говорить (например, говорят, что некоторый атрибут кортежа содержит "значение NULL"). Результатом любых операций сравнения, в которых один из операндов содержит неопределенное значение, служит третье истинностное значение, unknown (сокращенно — ипк), поэтому такая логика называется трехзначной. Кроме того, отмечалось, что, по крайней мере, концептуально может существовать много разных видов неопределенных значений, в частности, в качестве удобного (и явного) сокращения для той разновидности неопределенных значений, когда значение неизвестно, было введено сокращение UNK.

Далее исследовалось влияние использования величины UNK и трехзначной логики на вычисление логических операторов AND, OR и NOT (а также MAYBE), кванторов EXISTS и  FORALL,  других  скалярных  операторов,  реляционных   операторов  и  операторов обновления  INSERT  и  UPDATE. В  этой  главе  были  представлены  оператор  IS_UNK (проверяющий наличие величины UNK), оператор IF_UNK (для преобразования величины UNK в значение, отличное от UNK). Дополнительно обсуждалась проблема дубликатов кортежей с учетом присутствия величины UNK. Кроме того, было особо подчеркнуто, что величина UNK И логическое значение ипк — это не одно и то же.

Затем рассматривались некоторые следствия изложенных идей. Ьыло  показано, что некоторые эквивалентности двухзначной логики не являются эквивалентностями в трехзначной логике. В результате пользователи и программы-оптимизаторы СУБД могут совершать ошибки в процессе  преобразования выражений. Но даже без учета названных ошибок трехзначная логика обладает одним очень серьезным недостатком — она не соответствует реальному миру, т.е. результаты операций в трехзначной логике не всегда являются правильными в реальном мире.

Затем были описаны последствия присутствия неопределенных значений в первичных и внешних ключах (в частности, упоминались правила поддержки целостности сущностей и пересмотренное правило поддержки ссылочной целостности). Было сделано отступление для описания внешнего соединения. Отмечалось, что автор не является сторонником прямой поддержки этой операции (по крайней мере, в ее обычном смысле), так как считает, что существует лучшее решение той проблемы, которую призвано решать внешнее соединение. В частности, автор предлагает использовать подход на основе атрибутов со значениями в виде отношений. Также кратко рассматривалась возможность существования и других "внешних" операций, в частности операции внешнего объединения.

В данной главе проанализирована поддержка изложенных идей в стандарте языка

SQL. В трактовке проблемы отсутствия информации в стандарте языка SQL широко

используется трехзначная логика, но эта трактовка вносит множество осложнений, описание которых выходит за рамки данной книги. И действительно, в дополнение к собственным недостаткам трехзначной логики ([19.6], [19.10])  стандарт языка SQL вносит свои недостатки. Более того, эти дополнительные  недостатки, по сути, выступают как факторы замедления процесса оптимизации (более подробно это обсуждается в разделе

18.8главы 18).

В заключение попытаемся кратко сформулировать некоторые дополнительные замечания.

■     Читатель, безусловно, согласится, что проблемы, связанные с использованием неопределенных значений и трехзначной логики, описаны в книге несколько сжато. Тем не менее, здесь представлен достаточно большой объем материала, позволяющего убедиться в том, что "преимущества", достигаемые при использовании трехзначной логики, более чем сомнительны.

■       Следует также отметить, что даже если читатель не слишком озабочен проблемами, связанными с использованием трехзначной логики, ему все же рекомендуется избегать применения соответствующих возможностей языка SQL из-за упоминавшихся выше "дополнительных недостатков".

■     Исходя из всего сказанного, автор рекомендует пользователям СУБД полностью игнорировать   все   средства   поддержки   трехзначной   логики,   предоставленные разработчиком выбранного им продукта. Вместо них целесообразно использовать более  строгий  механизм  "специальных   значений"  (благодаря  своей  строгости остающийся в рамках двухзначной логики). Подобная схема подробно описана в [ 19.12].

■    Наконец, повторим важное утверждение, сформулированное в разделе 19.3. Говоря весьма неформально, если значение данного атрибута данного кортежа данного отношения "является неопределенным", то в этой позиции атрибута вообще ничего не содержится. Это означает, что данный "атрибут" уже не является атрибутом, что этот "кортеж" уже не является кортежем, что это "отношение" уже не является отношением и для обоснования наших дальнейших действий (какими бы они ни были) использовать математически строгую реляционную теорию уже нельзя.

Источник: Дейт К. Дж., Введение в системы баз данных, 8-е издание.: Пер. с англ. — М.: Издательский дом «Вильямс», 2005. — 1328 с.: ил. — Парал. тит. англ.

По теме:

  • Комментарии