Часть реляционной модели, связанная с целостностью данных, с годами подвергалась наибольшему изменению. Причина такого положения, несомненно, кроется в том, что эта часть модели, скажем прямо, имеет наименее твердую научную основу по сравнению с другими частями. Именно в этой области несколько раз изменялись некоторые основные определения, а некоторые аспекты отдельных версий этих определений имели догматический, а не логический характер. В этой главе даются определения и пояснения, которые в данный момент мы считаем предпочтительными; и вообще, мы старались представить материал так, как сочли необходимым во время написания книги. Там, где есть особенно серьезные отклонения от более ранних определений и описаний, мы даем некоторые замечания относительно этих изменений и их причин.
Начав с такой необычной преамбулы, продолжим в том же духе. Сначала немного философии.
1. В любой момент времени любая база данных
содержит некую определенную конфигурацию значений данных, и, конечно,
предполагается, что эта конфигурация "отражает Действительность",
т.е. является моделью или представлением части реального мира.
2. Просто определенная конфигурация значений
не имеет смысла, если значения в этой конфигурации не представляют
определенного состояния реального мира. Например, конфигурация для базы данных
поставщиков и деталей, которая в отношении Р содержала бы кортеж "деталь
Р7 весит минус 25 фунтов", наверное, не имела бы смысла, поскольку вес не
может быть отрицательным в реальном мире.
3. Следовательно, определение базы данных
нуждается в расширении, включающем правила целостности, назначение которых в
том, чтобы информировать СУБД о разного рода ограничениях реального мира (таких
как ограничение на вес детали, который не может быть отрицательным), а значит,
и предотвращать появление таких недопустимых конфигураций значений. В примере с
весом детали, конечно, все СУБД должны контролировать операции INSERT и UPDATE на отношении Р, а также отказывать в
выполнении операции, если в ней проводится попытка ввести отрицательное
значение атрибута веса.
Большинство баз данных подчиняется очень
многим правилам целостности, и это важно понимать. Например, список правил для
поставщиков и деталей мог бы легко включить следующие правила:
■
номера
поставщиков должны быть в форме Snnnn, где пппп может принимать значение до четырех десятичных
цифр;
■
номера
деталей должны быть в форме Рппппп, где ппппп может принимать
значение до пяти десятичных цифр;
■
значение
статуса поставщика должно быть в диапазоне 1-100;
■
города
поставщиков и деталей должны выбираться из определенного списка;
■
цвета
деталей должны выбираться из определенного списка;
■
вес деталей
должен быть больше нуля;
■
количество
при отправке должно быть умножено на 100;
■
все красные
детали должны сдаваться на хранение в Лондоне;
■
если город
поставщика — Лондон, то статус поставщика должен быть равен 20; и т.д.
Любое данное правило целостности является специфическим
для базы данных в том смысле, что оно применяется к одной конкретной
базе данных, и все вышеприведенные примеры в этом смысле, Очевидно, тоже
специфичны для определенной базы данных. Однако в дополнение к специфическим
правилам (которые кратко рассматриваются в следующей главе и подробно будут
описаны далее в этой книге) в реляционной модели есть два общих особых
правила целостности. Эти особые правила применяются к любой базе данных,
а не только к некоторым определенным, таким как базы данных поставщиков и
деталей. Эти два особых правила относятся к потенциальным (и первичным)
ключам и ко внешним ключам. Потенциальные и внешние ключи будут
рассмотрены ниже в этой главе.
Хотя основная идея потенциальных и внешних
ключей довольно проста, имеется, к сожалению, один осложняющий дело фактор— это
null-значения (неопределенные значения). Возможность
того, что данный внешний ключ может допускать null-значения, портит всю картину. Из
педагогических соображений при изложении материала вначале мы не будем
касаться, null-значений,
а рассмотрим их влияние позже в этой главе.
Прежде чем углубиться в детали, необходимо
сделать еще одно замечание. Правила целостности будут рассматриваться главным
образом с точки зрения их применения к базовым отношениям. Причина, конечно, в
том, что именно базовые отношения должны отражать действительность, а значит,
именно для базовых отношений необходимы ограничения по содержанию верной или,
по крайней мере правдоподобной, конфигурации значений. Однако на самом деле к
производным отношениям также применяются правила целостности. Например, если к
базовому отношению S
применимо правило, гласящее, что номер поставщика должен быть уникальным, это
правило, очевидно, также применимо к каждой выборке строк этого отношения.
Как видно из этого примера, производными
отношениями автоматически наследуются определенные правила целостности
отношений, от которых они произведены. Но возможно, что для производных
отношений существуют некоторые дополнительные правила целостности,
противоречащие или дополняющие автоматически наследуемые правила. А значит,
может возникнуть необходимость указать все правила целостности для определенных
производных отношений в явном виде. Примером тому может служить определение
потенциального ключа для представления.
Этот вопрос еще будет обсуждаться в
последующих главах. В этой главе мы ограничимся лишь базовыми отношениями,
потому что после их освоения можно перейти и к другому материалу. Но если вы не
справитесь с базовыми отношениями, то обо всем остальном нечего и думать.
В предыдущих главах уже не раз упоминались
первичные ключи; если говорить нестрого, то первичный ключ — это просто
уникальный идентификатор для некоторого отношения. Однако первичный ключ на
самом деле является частным случаем более общего понятия — потенциального ключа.
Вот определение последнего понятия. Пусть R — некоторое отношение. Тогда потенциальный ключ, скажем, К для
R — это подмножество множества атрибутов R, обладающее следующими свойствами:
1.
Свойством
уникальности.
Нет двух различных кортежей в отношении R с одинаковым значением К.
2.
Свойством
неизбыточности.
Никакое из подмножеств К не
обладает свойством уникальности.
Обратите внимание, что (как было указано в
главе 4) каждое отношение имеет, по крайней мере, один потенциальный
ключ, так как не содержит одинаковых кортежей; т.е. поскольку кортежи
уникальны, то, по крайней мере, комбинация всех атрибутов обладает свойством
уникальности и поэтому возможны два варианта.
■
Либо эта
комбинация обладает свойством неизбыточности, а значит, будет потенциальным
ключом (на самом деле единственным потенциальным ключом).
■
Либо
существует по крайней мере одно подходящее подмножество этой комбинации,
заведомо обладающее свойством уникальности и к тому же обладающее свойством
неизбыточности.
(Обсуждение свойства неизбыточности
смотрите ниже.) На практике вместо необходимости использовать все атрибуты, как
правило, подходит некоторая меньшая комбинация. Конечно, возможно отношение, в
котором единственным потенциальным ключом будет комбинация всех атрибутов, т.е.
отношение будет "сплошным ключом". Примером такого отношения может
служить отношение SP
из базы данных поставщиков и деталей, если убрать из него атрибут QTY.
Обратите особое внимание на то, что данное
выше определение потенциального ключа относится к самому отношению (т.е.
к значениям отношения), а не к переменным отношения. Когда мы
рассматриваем переменные отношения, особенно базовые отношения, то
концентрируем свое внимание с точки зрения целостности не столько на
определенном отношении, ставшем 'значением переменной отношения в определенный
момент времени, сколько на множестве всех возможных отношений, которые
могут быть значениями этой переменной.
■
Например,
если мы говорим, что комбинация атрибутов {S#, P#} — это потенциальный ключ для базового
отношения SP,
мы не имеем в виду, что просто в данный момент в отношении нет двух кортежей с
одинаковым значением этой комбинации; мы имеем в виду, что для всех возможных
отношений R, которые
могут быть значениями SP, нет двух различных кортежей отношения R с одинаковым значением этой комбинации.
Поэтому для переменных отношения нам нужно дополнить определение потенциального
ключа следующим образом (дополнения выделены жирным).
Пусть R — некоторая переменная отношения. Тогда потенциальный ключ,
скажем, К для R — это
подмножество множества атрибутов Я, всегда обладающее следующими свойствами:
1.
Свойством
уникальности.
Нет двух различных кортежей в текущем
значении переменной R с одинаковым
значением К.
2.
Свойством
неизбыточности.
Никакое из подмножеств К не
обладает свойством уникальности.
Впредь будем использовать термин
"потенциальный ключ" в этом более требовательном значении (за
исключением специальных оговорок).
Ниже приведен синтаксис операторов
определения потенциального ключа для базового отношения (отметьте, что каждый
оператор create base relation должен включать в себя, по крайней мере, одно определение
потенциального ключа):
candidate-key-definition
::= CANDIDATE
KEY (attribute-commalist)
׀ PRIMARY KEY (attribute-commalist)
Примеры смотрите на рис. 3.9 и 4.3. (Однако обратите внимание, что
на этих рисунках показан лишь случай первичного, а не потенциального ключа.
Случай потенциального ключа обсуждается далее в этой главе.)
Прежде чем
продолжить дискуссию о важности потенциальных ключей, нам необходимо выяснить
несколько весьма важных вопросов.
■
Во-первых, хотя на практике отношения чаще всего имеют только один
потенциальный ключ, их, конечно же, может быть несколько. Пусть, например, у
нас есть отношение ELEMENTS, представляющее
таблицу химических элементов. У каждого элемента есть уникальное имя, уникальное
обозначение (например, обозначение свинца — "Рb") и уникальное атомное число. Поэтому ясно, что в отношении
есть три различных потенциальных ключа:
CREATE BASE RELATION
ELEMENTS
(NAME … ,
SYMBOL … ,
NUMBER … ,
… … ,
CANDIDATE KEY (NAME)
CANDIDATE KEY (SYMBOL)
CANDIDATE KEY (NUMBER)
■
Во-вторых, заметьте, что потенциальные ключи определены как множества
атрибутов. Поэтому при ссылке на них используются "скобки
множества", т.е. фигурные скобки. Например, в базе данных поставщиков и
деталей {S#} — это потенциальный ключ
отношения S, (Р#) — это потенциальный ключ
отношения Р, {S#, P#} — это потенциальный ключ отношения SP. Однако в неформальном контексте скобки обычно опускают, если это
множество содержит только один атрибут. Поэтому можно сказать, например, что S# (вместо {S#}) — это
потенциальный ключ отношения S.
Терминология. Потенциальный
ключ, состоящий из более чем одного атрибута, называется составным. Потенциальный
ключ, состоящий из одного атрибута, называется простым.
Кроме того,
понятие неизбыточности требует некоторого уточнения. Дело в том, что, если мы
определили "потенциальный ключ", не являющийся неизбыточным,
системе не будет известно об этом и потому она не сможет обеспечить должным
образом соответствующее ограничение целостности. Пусть, например, мы определили
потенциальный ключ отношения S как комбинацию {S#,CITY} вместо S#. Тогда система не сможет соблюдать ограничение, обеспечивающее
уникальность номера поставщика в "глобальном смысле"; вместо этого в
системе будет выполняться более слабое ограничение, согласно которому номер
поставщика будет уникальным в "локальном смысле", т.е. в пределах
одного города. Таким образом, настоящие потенциальные ключи не должны включать
лишних атрибутов для идентификации уникальности.
Замечание. Есть еще одна
серьезная причина требования неизбыточности потенциальных ключей, которая
связана с внешними ключами. Дело в том, что любой внешний ключ, на
который ссылается "избыточный" потенциальный ключ (если бы такое было
возможно), был бы также "избыточным" и отношение, содержащее его,
практически наверняка противоречило бы принципам дальнейшей нормализации.
Между прочим, в
этом смысле в литературе (включая предыдущие издания этой книги) неизбыточность
часто называют минимальностью. Однако "минимальность" — это не
совсем точное выражение, поскольку, когда мы говорим, что потенциальный
ключ К1 "минимален", мы не имеем в виду, что не существует
другого потенциального ключа К2 с меньшим количеством атрибутов; вполне
возможно, что, например, ключ K1 состоит из
четырех атрибутов, а ключ К2 только из двух. Поэтому мы будем
использовать термин "неизбыточность".
■
И наконец, обратите внимание на то, что логическое понятие
потенциального ключа не следует путать с физическим понятием уникального
индекса, хотя последний часто играет роль потенциального ключа. Другими
словами, вовсе не обязательно должен существовать индекс (или другой
специальный путь доступа, сводящийся к индексу) по потенциальному ключу.
Конечно, на практике такой специальный путь доступа будет существовать,
но вопрос о том, существует он или нет, выходит за рамки модели как таковой.
Причина такой важности потенциальных ключей заключается в том, что
они обеспечивают основной механизм адресации на уровне кортежей в
реляционной системе. Следовательно, единственный гарантируемый системой способ
точно указать на какой-нибудь кортеж — это указать значение некоторого
потенциального ключа. Например, с помощью выражения
мы
гарантированно получим не больше одного кортежа.1
Аналогично, если атрибут SNAME также будет
потенциальным ключом для отношения S (обратите
внимание, что данные, приведенные на рис. 4.6, согласуются с этой гипотезой), с
помощью выражения
мы также
гарантированно получим не более одного кортежа. Но с помощью выражения "
мы получим в
общем случае количество кортежей, которое нельзя предсказать. Таким образом, потенциальные
ключи имеют такое же фундаментальное значение для успешной работы реляционной
системы, как адресация основной памяти для успешной работы машины, на которой
эта система установлена. И в качестве выводов приведем следующее:
1. "Отношения",
которые не имеют потенциальных ключей, т.е. "отношения", допускающие
дублирование кортежей, ограничивают отображение нарушений или отклонений от
нормального режима работы в определенных обстоятельствах.
2. Система, в
которой не используются потенциальные ключи, иногда ограничена в возможностях
отображения состояния, которое не является «действительно реляционным», даже
если используемые в ней отношения и не допускают дублирования кортежей.
Упоминающееся выше поведение с
«нарушениями или отклонениями» и «не совсем реляционное», связано с такими
процессами, как обновление представлений и оптимизация. (Но
об этом в следующих частях книги.)
Как мы уже убедились, базовое отношение
может иметь (хотя это, возможно, редко применяется) больше одного
потенциального ключа. В таком случае в реляционной модели по традиции один из потенциальных
ключей должен быть выбран в качестве первичного ключа в базовом
отношении, а остальные потенциальные ключи, если они есть, будут называться альтернативными
ключами. В примере отношения ELEMENTS, приведенном выше в этой главе, мы можем выбрать
"обозначение элемента" в качестве первичного ключа, тогда
"название элемента" и "атомное число" будут альтернативными
ключами. В случае же, когда есть лишь один потенциальный ключ, в реляционной
модели, опять же традиционно, он должен быть выбран в качестве первичного
ключа в базовом отношении. Следовательно, каждое базовое отношение должно
всегда иметь первичный ключ.
Замечание. Если множество потенциальных ключей имеет
более одного элемента, то выбор ключа в качестве первичного, по существу, может
быть произвольным.
Наше мнение по этому вопросу следующее:
выбор одного потенциального ключа (если есть из чего выбирать) в качестве
первичного определенно желателен во многих случаях (даже в большинстве
случаев), но это не подтверждается во всех случаях, Аргументы в пользу
этой точки зрения даны в [5.8].
Конечно, если в отношении лишь один
потенциальный ключ, то именование его первичным вызывает небольшое раздражение.
Но если есть несколько потенциальных ключей, то выбор одного из них в качестве
первичного может быть во многих ситуациях весьма полезным (хотя с философской
точки зрения это выходит за рамки модели как таковой). Другими словами,
первичные ключи могут еще отстаивать свою немалую практическую (или по
крайней мере историческую) важность. Поэтому ниже приведен синтаксис для их
объявления. Но мы не настаиваем на том, что каждое базовое отношение должно
иметь первичный ключ, а лишь подчеркиваем, что каждое базовое отношение должно
иметь по крайней мере один потенциальный ключ.
Что касается наших собственных примеров, в
основном, но не постоянно мы будем соблюдать правило первичных ключей,
т.е. большинство наших базовых отношений будет иметь первичный ключ (и мы будем
продолжать помечать первичные ключи в рисунках двойным подчеркиванием).
Вот соответствующий синтаксис (он уже приводился выше в этой главе):
:: = CANDIDATE KEY ( attribute-coimmalist )
|PRIMARY KEY ( attribute-commalist
)
(Как уже упоминалось ранее, commalist означает список указанных элементов через запятую.)
Внутри любого конкретного оператора create base relation должно быть, по крайней мере, одно
определение потенциального ключа. Но лишь одно из этих определений может
объявлять первичный ключ, т.е. только в одном определении может содержаться
выражение primary key.
И последнее замечание относительно
терминологии. Термины "потенциальный ключ" и "первичный
ключ" не должны заменяться простым сокращением ключ. Термин
"ключ" уже имеет слишком много значений в мире баз данных. Например,
только одна реляционная модель имеет потенциальные, альтернативные, первичные и
внешние ключи. В других контекстах используются такие понятия, как индексные
ключи, хеш-ключи, ключи сортировки, вторичные ключи, поисковые ключи, основные
ключи, подчиненные ключи, ключи шифрования, ключи расшифровки, ключи
секретности и т.д., пока не надоест. Поэтому предпочтительнее, по мнению
автора, всегда использовать термины по назначению, чтобы избежать
возможной путаницы.
(В предыдущем издании этой книги мы
договорились, что если какой-нибудь один ключ и заслуживает называться этим
термином (просто "ключ") и быть выделенным из всего многообразия
ключей, то это, очевидно, первичный ключ! Сейчас нам кажется, что если
неудачный термин "ключ" использовать всегда, то было бы правильнее использовать
его в значении потенциальный ключ. Тот факт, что мы изменили свое мнение
в этом отношении, придает еще больший вес первоначальному аргументу, что
термины должны быть всегда наиболее подходящими.)
Обратимся вновь к базе данных поставщиков
и деталей и рассмотрим атрибут S# отношения SP. Ясно, что данное значение для такого атрибута должно быть
допустимо для базы данных лишь в случае, если такое же значение существует в
качестве значения первичного ключа S# отношения S (в противном случае база данных не может рассматриваться как
целостная). Например, не имело бы смысла включать для отношения SP поставку для поставщика, скажем, S8, если бы в отношении S не существовало поставщика S8. Аналогично, данное значение для
атрибута Р# отношения SP должно быть допустимо для базы данных лишь в случае, если такое
же значение есть в качестве значения первичного ключа Р# отношения Р; и опять
же не имело бы смысла включать для отношения SP поставку для поставщика, скажем, Р8, если
бы в отношении Р не существовало поставщика Р8. Атрибуты S# и Р# отношения SP, таким образом, являются примерами того,
что мы называем внешними ключами.
Прежде чем продолжить, следует обратить
внимание на то, что мы затронули область, в которой ведется дискуссия по
определенным вопросам. Реляционная модель традиционно требует, чтобы внешние
ключи в точности соответствовали первичным ключам, а не просто потенциальным
ключам (например, [5.2]). Эта позиция поддерживается и в предыдущей редакции
этой книги, и в других публикациях автора (например, [5.3, 5.4]). Однако наша
сегодняшняя позиция сходна с позицией по первичным ключам вообще: требование
точного соответствия внешних ключей первичным желательно во многих случаях,
даже в большинстве случаев; но это не подтверждается во всех случаях.
(Аргументы в поддержку этой позиции можно найти в [5.8].) Что касается примеров
в этой книге, то мы придерживались правила о том, что внешние ключи в
действительности ссылаются точно на первичные ключи; однако делалось это только
для того, чтобы упростить описание.
Пришло время уточнить основные идеи. Вот
определение термина "внешний ключ".
Пусть R2— базовое отношение. Тогда внешний ключ, скажем, FK в отношении R2 — это подмножество множества атрибутов R2, такое что:
■
существует
базовое отношение R1 (R1 и R2 не обязательно различны) с потенциальным ключом СК;
■
каждое
значение FK в
текущем значении R2 всегда
совпадает со значением СК некоторого кортежа в текущем значении R1. Определение нуждается в пояснениях.
1.
Заметьте,
что внешние ключи, как и потенциальные, определены как множества атрибутов.
Поэтому для них необходимо использовать "скобки множества" (фигурные
скобки). Например, в отношении SP базы данных поставщиков и деталей внешние ключи, строго говоря, —
это {S#}
и {Р#}, а не S# и
Р#. Однако в неформальном контексте скобки обычно опускают, если это множество
содержит только один атрибут.
2.
По
определению каждое значение данного внешнего ключа должно являться значением
соответствующего потенциального ключа. Однако заметьте, что обратное не требуется;
т.е. потенциальный ключ, соответствующий данному внешнему ключу, может
содержать значение, которое в данный момент не является значением внешнего
ключа. Например, в случае базы данных поставщиков и деталей (примерные значения
показаны на рис. 3.8) поставщик с номером S5 не поставляет в данный момент никаких
деталей.
3.
Данный
внешний ключ будет составным, т.е. будет состоять из более чем одного
атрибута, тогда и только тогда, когда соответствующий потенциальный ключ также
будет составным. Он будет простым тогда и только тогда, когда
соответствующий потенциальный ключ также будет простым.
4.
Каждый
атрибут, входящий в данный внешний ключ, должен быть определен на том же
домене, что и соответствующий атрибут соответствующего потенциального ключа.
5.
Для внешнего
ключа не требуется, чтобы он был компонентом первичного ключа или какого-либо
потенциального ключа в содержащем его отношении, хотя в примере базы данных
поставщиков и деталей оба внешних ключа обладают таким свойством (в
действительности два внешних ключа в отношении SP вместе составляют первичный ключ
этого отношения). Вот еще один пример (определение базы данных отделов и
сотрудников из главы 3, рис. 3.6, показано в упрощенной форме):

В этой базе данных атрибут DEPT# отношения ЕМР является внешним ключом,
соответствующим первичному ключу DEPT# отношения DEPT; однако он, конечно, не является компонентом первичного ключа
ЕМР# (и никакого другого потенциального ключа) отношения ЕМР. В
действительности внешним ключом может быть любой атрибут или какое-либо
сочетание атрибутов (в базовом отношении).
6.
Терминология.
Значение внешнего ключа
представлено ссылкой к кортежу, содержащему соответствующее значение
потенциального ключа (ссылочный кортеж или целевой кортеж). Поэтому
проблема обеспечения того, что база данных не включает никаких неверных
значений внешних ключей, известна как проблема ссылочной целостности.
Ограничение, по которому значения данного внешнего ключа должны быть адекватны
значениям соответствующих потенциальных ключей, называют ссылочным
ограничением. Отношение, которое содержит внешний ключ, называется ссылающимся
отношением, а отношение, которое содержит соответствующий потенциальный
ключ, — ссылочным отношением или целевым отношением (target relation).
7.
Ссылочные
диаграммы. Рассмотрим
снова базу данных поставщиков и деталей. Существующие в базе данных ссылочные
ограничения можно представить средствами следующей ссылочной диаграммы:
![]()
Каждая стрелка обозначает здесь внешний ключ в отношении, из которого стрелка выходит; этот ключ специфически ссылается на первичный ключ отношения, на который стрелка указывает.
Замечание. Для простоты здесь игнорируется небольшая
тонкость, которую необходимо учитывать, когда имеешь дело с внешним ключом,
ссылающимся на потенциальный ключ, не являющийся первичным ключом. Но
необходимо отметить, что иногда желательно помечать каждую стрелку в ссылочной
диаграмме именами атрибутов (именем атрибута), которые составляют
соответствующий внешний ключ. Например:

В этой книге, однако, мы будем
использовать такие пометки лишь в тех случаях, когда их отсутствие может
привести к путанице или двусмысленности.
8.
Отношение,
конечно, может быть одновременно ссылочным и ссылающимся, как в случае
отношения R2 в
следующей диаграмме:
![]()
Удобно ввести термин "ссылочный
путь". Пусть отношения Rn, R(n-1), ..., R2, R1 такие, что имеется ссылочное ограничение из Rn в R(n-1), ссылочное ограничение из R(n-1) в R(n-2),... и ссылочное ограничение из R2 в R1:
![]()
Тогда цепочка стрелок из Rn в R1 представляет ссылочный путь из Rn в R1
9.
Заметьте,
что отношения R1 и R2 в определении внешних ключей не обязательно различны, т.е.
некоторое отношение может включать внешний ключ, значения которого должны
соответствовать значениям некоторых потенциальных ключей в том же отношении. В
качестве примера рассмотрим следующее отношение:

В этом отношении атрибут MGR_EMP# представляет номер служащего для менеджера, который
идентифицируется атрибутом ЕМР# как служащий. Здесь ЕМР# — первичный ключ, a MGR_EMP# — внешний ключ, который ссылается на этот первичный.
(Например, кортеж для служащего Е4 может включать значение MGR_EMP# кортежа ЕЗ, который представляет ссылку к кортежу ЕМР для
служащего ЕЗ. Ниже будет разъяснена конструкция RENAME.) Такие отношения иногда называют
самоссылающимися.
10.
Самоссылающиеся
отношения, такие как отношение ЕМР в предыдущем примере, в действительности
представляют собой специальный случай более общей ситуации, когда могут
возникать ссылочные циклы. Отношения Rn, R(n-1),..., R2, R1 образуют ссылочный цикл, если отношение Rn включает внешний ключ, ссылающийся на R(n-1), отношение R(n-1) включает
внешний ключ, ссылающийся на R(n-2), ... и наконец, отношение R1 включает внешний ключ, ссылающийся вновь на Rn. Или более кратко: ссылочный цикл существует, если есть ссылочный
путь из некоторого отношения Rn к себе:
![]()
11.
Соответствие
внешний к потенциальному ключу иногда называют "клеем", который
удерживает базу данных как единое целое. То же самое можно сказать и иначе:
такое соответствие представляет собой некоторое отношение или
взаимосвязь между кортежами. Однако обратите внимание, что не все отношения
представлены этими соответствиями. Например, есть, отношение между размещенными
в одном городе поставщиками и деталями, представленное атрибутами CITY отношений S и Р. Однако такие атрибуты CITY не являются внешними ключами. Они могли
бы стать внешними ключами, если бы в базу данных было добавлено
отношение с атрибутом CITY как потенциальным ключом.
Вот синтаксис для указания внешнего ключа
(обратите внимание, что данный оператор CREATE BASE RELATION может включать нуль или более определений внешних ключей):
FOREIGN KEY (element-commalist) REFERENCES base-relation
Синтаксис категории element здесь представлен или именем атрибута базового отношения,
содержащего его (обычный случай), или выражением вида
Здесь первый параметр attribute является именем атрибута содержащего его отношения, а второй
параметр attribute представляет собой новое имя для такого
атрибута, который реально заменяет первое имя при работе с данным внешним
ключом. Полное множество имен атрибутов для внешнего ключа должно совпадать с
множеством имен атрибутов для некоторого потенциального ключа базового
отношения, указанного после оператора REERENCES. Некоторые примеры можно найти на рис.
3.9 или 4.3 (простой случай); также смотрите выше пример внешнего ключа MGR_EMP# (случай с использованием оператора RENAME).
Дальнейшее обсуждение применения оператора rename будет приведено в следующих главах книги.
Вместе с понятием внешнего ключа
реляционная модель включает следующее правило (правило ссылочной целостности):
■
Ссылочная
целостность.
База данных не должна содержать
несогласованных значений внешних ключей.
Здесь "несогласованное значение
внешнего ключа" — это значение внешнего ключа, для которого не
существует отвечающего ему значения соответствующего потенциального ключа в
соответствующем целевом отношении. Проще говоря, правило утверждает, что если В
ссылается на А, тогда А должно существовать.
И наконец, отметим, что понятия
"внешний ключ" и "ссылочная целостность" определены в
терминах друг друга. То есть невозможно объяснить, что такое внешний ключ,
без упоминания понятия ссылочной целостности (по крайней мере, неявным
образом), и точно так же невозможно объяснить, что такое ссылочная целостность,
без упоминания понятия внешнего ключа (опять-таки, по крайней мере, неявным
образом). Таким образом, понятия "поддержка ссылочной целостности" и
"поддержка внешних ключей" означают в точности одно и то же.
Правило целостности, сформулированное в
предыдущем разделе, выражено исключительно в терминах состояний базы
данных. Любое состояние базы данных, не удовлетворяющее этому правилу,
некорректно; но как избежать таких некорректных состояний? В самом правиле об
этом не говорится.
Одна из возможностей состоит в том, чтобы
просто запретить любые операции, приводящие к некорректному состоянию. Однако в
некоторых случаях предпочтительнее допустить такую операцию, но при
необходимости выполнить некоторые компенсирующие операции, чтобы гарантировать,
что в результате система останется в корректном состоянии. Например, если
пользователь пытается удалить поставщика S1 из отношения S, система сама может удалить поставки
поставщика S1
из отношения SP
без каких-либо последующих действий со стороны пользователя (предполагается,
конечно, что требовалось получить именно такой результат "каскадного
удаления").
Следовательно, для этой базы данных у
пользователя (или в этом контексте у разработчика базы данных) должна
быть возможность определить, какие операции должны быть запрещены, а какие
разрешены, нужны ли для разрешенных операций компенсирующие, и если да, то
какие. Поэтому мы кратко обсудим эту возможность в настоящем разделе. Однако
заметьте, что при этом мы выходим за рамки обсуждения самой реляционной модели.
Основная идея состоит в следующем. Для
каждого внешнего ключа необходимо ответить на два важных вопроса.
1.
Что должно
случиться при попытке удалить объект ссылки внешнего ключа? Например, удалить
поставщика, для которого есть, по крайней мере, одна поставка. Для определенности
рассмотрим именно этот случай. В общем существует по меньшей мере две
возможности: ,
•
ОГРАНИЧИТЬ —
"ограничить" операцию удаления, до момента, когда не будет
существовать соответствующих поставок (в противном случае операция
запрещается);
•
КАСКАДИРОВАТЬ
— "каскадировать" операцию удаления, удаляя также соответствующие
поставки.
2.
Что должно
случиться при попытке обновить потенциальный ключ, на который ссылается внешний
ключ? Например, при попытке обновить номер поставщика, для которого существует,
по крайней мере, одна соответствующая поставка. И вновь рассмотрим именно этот
случай для определенности. Как и для удаления здесь существует по меньшей мере
две возможности:
•
• ОГРАНИЧИТЬ
— "ограничить" операцию обновления до момента, когда не будет
существовать соответствующих поставок (в противном случае операция
запрещается);
•
•
КАСКАДИРОВАТЬ — "каскадировать" операцию обновления, обновляя также
внешний ключ в соответствующих поставках.
Исходя из вышесказанного, разработчик при
проектировании внешних ключей базы данных должен не только указать атрибут или
комбинацию атрибутов, составляющую данный внешний ключ в соответствующем
целевом отношении, но и ответить на указанные выше вопросы (т.е. указать
специальные правила внешних ключей для данного внешнего ключа). Поэтому нам
необходимо расширить синтаксис определения внешнего ключа следующим образом:

Здесь параметр option может принимать значение RESTRICTED (ограничить) или CASCADES (каскадировать). В связи с этим возникают
следующие вопросы.
1.
Конечно,
опции RESTRICTED и CASCADES для правил удаления и обновления внешнего
ключа не ограничивают возможности: они лишь представляют два случая, которые
обычно используются на практике. А в принципе может быть любое количество
возможностей при попытке удаления определенного поставщика. Например:
•
может быть
инициирован диалог с конечным пользователем;
•
информация
может быть занесена в некоторую архивную базу данных;
•
поставки
удаляемого поставщика могут быть приписаны какому-либо другому поставщику.
Конечно, дать названия всем возможным
действиям нереально. Поэтому в общем случае параметр option в нашем синтаксисе должен включать
возможность вызова определенной при установке процедуры баз данных (иногда
называемой "хранимой процедурой" или "процедурой
триггеров").
2.
Пусть R1 и R2 — соответственно ссылающееся и ссылочное отношение (R2 ®R1).
И пусть для этого ссылочного ограничения
установлено правило каскадного удаления, т.е. удаление данного кортежа из
отношения R1 повлечет
удаление определенных кортежей отношения R2 (в общем случае). Теперь предположим, что на отношение R2, в свою очередь, ссылается некоторое отношение R3:
![]()
Тогда неявное удаление кортежей отношения R2 рассматривается как попытка удалить эти кортежи непосредственно;
т.е. оно зависит от правила удаления, определенного для ссылочного ограничения
из R3 к R2. Если это неявное удаление не выполняется (согласно правилу
удаления для ссылочной зависимости R3 от R2 или по
другой причине), то не выполняется и вся операция, и база данных остается
неизмененной. И так далее рекурсивно для любого количества уровней.
Аналогичные замечания можно сделать также
относительно правила каскадного обновления с необходимыми изменениями, если
внешний ключ в отношении R2 имеет
какие-либо совместные атрибуты с потенциальным ключом того отношения, на
которое ссылается внешний ключ в отношении R3.
Из сказанного выше следует, что с
логической точки зрения операции обновления базы данных всегда атомарны (все
или ничего), даже если под прикрытием они выполняют несколько обновлений
нескольких отношений вследствие, например, правила каскадного удаления.
3.
То
обстоятельство, что могут возникать ссылочные циклы, вероятно, означает, что
некоторые проверки ограничений не могут быть выполнены во время отдельного
обновления, а вместо этого должны быть отложены на более позднее время,
например на время фиксации (эта тема выходит за рамки данной части). В
противном случае не будет возможности вставить кортеж в базу данных.
Сейчас мы объяснили основные идеи, лежащие
в основе понятий потенциальных и внешних ключей в реляционной модели. К
сожалению, существует один главный усложняющий фактор, который мы умышленно
игнорировали до сих пор, — null-значения.
Тема null-значений представляет собой
самостоятельный весьма обширный предмет обсуждения, она будет рассматриваться в
следующих частях книги. Но, чтобы объяснить роль null-значений для целостности в реляционной
модели, очевидно, необходимо сначала немного рассказать о null-значениях вообще. Поэтому данный раздел
можно считать кратким введением для этого понятия.
Когда говорят о null-значениях, то в основном подразумевают
базис, используемый при решении проблемы отсутствующей информации. Эта
проблема наиболее часто встречается в реальной жизни. Например, в исторических
записях иногда встречаются такие, как "Дата рождения неизвестна"; в
повестке дня собрания часто докладчик указан, как "Будет объявлен";
полицейские доклады могут включать такие записи, как "В настоящее время
местонахождение неизвестно". Следовательно, необходимо иметь некоторый
подход, когда сталкиваешься с такими ситуациями в формальных системах баз данных.
В [5.1] Коддом был предложен подход к этой
проблеме, в котором для представления отсутствующей информации используются
специальные маркеры, называемые null-значениями. Идея заключается в следующем: если данный
кортеж имеет null-значение
в данной позиции атрибута, то это означает, что в таком кортеже значение
атрибута по некоторой причине отсутствует. Например, кортеж поставки может
иметь null QTY (количество) — нам известно, что поставка
существует, но неизвестно количество отгружаемого; или деталь может иметь COLOR (цвет) null — возможно, покраска не применяется для
некоторых видов деталей или не имеет значения. Обратите внимание, null-значения — это не то же самое, что пробелы или числовые
нули; фактически они вообще не являются реальными значениями в обычном смысле
этого, термина, поэтому мы и назвали их "маркерами" (и поэтому, между
прочим, общепринятый термин "нулевое значение" резко осуждается).
В общем, для данного атрибута может быть
разрешено или не разрешено содержать null-значения; это будет зависеть от определения данного
атрибута, по крайней мере, для базовых отношений. (Иначе говоря, синтаксис
"определения атрибута" в операторе create base relation должен быть расширен для включения
спецификации вида nulls
allowed (null – значения допустимы) или nulls not allowed (null-значения не допустимы)). Если данному
атрибуту не разрешено содержать null-значения, система будет отвергать любые
попытки ввода null-значения
в эту позицию.
Как уже отмечалось, мы не намерены
рассматривать здесь содержание понятия null-значений во всех деталях. Но хотелось бы
внести ясность: по нашему мнению, null-значения — и целая теория трехзначной логики, на
которой они базируются, — являются фундаментальным заблуждением и не
должны иметь места в чистой формальной системе, такой какой подразумевается
реляционная модель. На самом деле, мы считаем, что: а) проблема отсутствия
информации еще не до конца осмыслена; б) в настоящее время не известно ни
одного полного удовлетворительного решения проблемы; в) включение null-значений или любых других подобных
свойств в модель на сегодняшний день преждевременно. Но нужно также
подчеркнуть, что другие авторы полагают совсем противоположное: в частности,
Кодд фактически рассматривает null-значения как неотъемлемую часть реляционной модели [4.4].
Как бы то ни было, давайте возвратимся к
главной теме нашего обсуждения и рассмотрим влияние null-значений на концепции потенциальных и
внешних ключей, которые описывались ранее.
Как разъяснялось выше в этой главе,
реляционная модель традиционно требует, чтобы (для базовых отношений, по
крайней мере) в качестве первичного ключа для данного отношения был
выбран ровно один потенциальный ключ, а оставшиеся ключи, если они есть, были
бы тогда альтернативными ключами. Вместе с понятием первичного ключа
модель включает правило целостности объектов:
■
Целостность
объектов. Ни один элемент
первичного ключа базового отношения не может быть null-значением.
Другими словами, определение каждого
атрибута первичного ключа любого базового отношения должно явно или неявно
включать спецификацию null not allowed.
Это правило объясняется следующим:
■
Базовые
отношения, точнее, кортежи базовых отношений соответствуют объектам в
реальном мире. Например, базовое отношение S соответствует реальным поставщикам.
■
По
определению объекты реального мира различимы, т.е. они некоторым образом опознаваемы.
■
Поэтому
соответствующие представления объектов в базе данных также должны быть
различимы (опознаваемы).
■
В
реляционной модели первичные ключи выполняют функцию уникальной идентификации
(т.е. служат для представления необходимых идентификаторов объектов).
■
Поэтому в
качестве примера предположим, что базовое отношение S включает кортеж, для которого значение $#
является null-значением.
Тогда можно сказать, что есть реальный поставщик, который не имеет идентичности
(по крайней мере, идентичность его не установлена).
■
Более того,
что такое null-значение
означает? Если это означает, что "свойство не применяется", то,
очевидно, такой кортеж не имеет смысла; как разъяснялось выше, объекты должны
обладать идентичностью, следовательно, свойство должно применяться.
Если это означает "неизвестное значение", то количество всевозможных
проблем возрастет. Например, мы сейчас еще даже не знаем (в общем),
представляет ли кортеж одного из поставщиков, о котором мы знаем (поскольку
неизвестно, что значит "не знаем"!): Таким образом, например, на
вопрос: "Сколько имеется поставщиков?"— следует ответ: "Не знаем".
■
Точно такие
же аргументы применимы и ко всем остальным возможным интерпретациям null-значения. На самом деле объект с
отсутствующей идентичностью является противоречием, Которое выражается
так: "Объект, который не имеет идентичности, не существует" (поэтому
правило и называется правилом "целостности объекта").
■
Аргументы,
аналогичные предыдущим, могут использоваться для демонстрации того, что в
базовом отношении с составным .первичным ключом значения первичного ключа,
которые являются частично null-значениями, должны быть также запрещены.
■
Подытожим:
если реальный объект настолько важен, что требуется его явное представление в
базе данных, то этот объект должен быть определенно и недвусмысленно
идентифицируемым, в противном случае какие бы то ни было разумные рассуждения о
нем не возможны. Поэтому правило целостности объектов иногда формулируют в
следующей форме:
В реляционной базе данных мы никогда не
записываем информацию о чем-то, чего мы не можем идентифицировать.
Мимоходом отметим общепринятое, но ошибочное
мнение, что правило целостности объектов гласит нечто в духе: "Первичные
ключи должны быть уникальны". Это не так. Уникальность первичных ключей
требуется в части основного определения понятия первичных ключей как
таковых. Правило же целостности объектов гласит (повторяем), что первичные
ключи в базовых отношениях не должны содержать ни одного null-значения.
Теперь давайте поближе рассмотрим это
правило. Поскольку оно использует не одно, а два понятия — первичные ключи и null-значения, в которых мы нашли нечто,
подвергаемое сомнению. Здесь необходимо сделать еще несколько замечаний.
■
Это правило
применяется только для базовых отношений. Другие отношения действительно
могут иметь первичный ключ, для которого null-значения допустимы. Приведем простой пример.
Предположим, что для цвета детали "допустимы null-значения" и что в отношении Р есть
дополнительный кортеж, скажем, для детали Р7, в котором атрибут COLOR (цвет) на самом деле является null-значением. Теперь рассмотрим отношение,
представляющее собой результат запроса "Список всех цветов деталей".
Такое отношение просто имеет один атрибут, который является потенциальным
ключом и, следовательно, первичным ключом, а один из кортежей отношения имеет null-значение в области первичного ключа.
Таким образом, правило целостности объектов предполагает неприятт ное (и
совершенно неоправданное) разграничение между базовыми и другими отношениями.
Что случится, если мы, например, попытаемся сохранить результат запроса
"Список всех цветов деталей" как новое базовое отношение?
■
Это правило
применяется только для первичных ключей. Для альтернативных ключей
null-значения могут
быть запрещены или разрешены. Но если альтернативный ключ является таким, для
которого разрешены null-значения,
то он не может быть выбран в качестве первичного ключа по правилу целостности
объектов. Так каков же точный смысл выражения, что альтернативный ключ является
"потенциальным" ключом в первую очередь? И наоборот, если мы говорим,
что альтернативные ключи также не должны иметь null-значений, тогда правило целостности
объектов должно относиться ко всем потенциальным ключам — а не только к
первичному ключу.
■
В
действительности объяснение правила целостности объектов, данное выше,
применимо в равной мере к каждому атрибуту всех базовых отношений, а
следовательно, null-значения
должны быть запрещены везде! Так для чего же предназначены null-значения?
■
Относительно
понятия первичных ключей в [5.2] было предложено запретить ссылаться к
первичным ключам, которым разрешены null-значения, именно как к первичным ключам, а ссылаться лишь
как к "слабым идентификаторам". Другими словами, некоторые отношения
не будут иметь собственного уникального идентификатора совсем. По нашему
мнению, в этом нет ничего страшного, но весьма сомнительно поддерживать
заведомо подозрительную позицию. Более того, в [4.4] автор настаивает на
требовании, чтобы кортежи, которые в каждой позиции атрибута ничего кроме null-значений не содержат, "мягко и
неожиданно исчезли", что кажется еще более подозрительным.
■
Предположим,
что мы полностью отказались от идеи null-значений и вместо представления отсутствующей информации
используем значения по умолчанию (т.е. так, как мы поступаем на
практике). Например, если зарплата служащего Джо не известна по некоторым
причинам, мы можем представить это в базе данных с помощью значения -1
(обсуждение этого вопроса приводится в дальнейших главах книги). Тогда правило
целостности объекта не имело бы больше никакого значения и могло бы быть
отброшено безо всякого ущерба.
Замечание. Мы, возможно, захотим сохранить измененную
версию этого правила "Никаким первичным ключам базовых отношений не
разрешается принимать значения по умолчанию" в качестве генеральной
линии, а не как нерушимое правило (почти так же, как идея дальнейшей
нормализации служит генеральной линией, а не является нерушимым правилом). На
рис. 5.1 приведен пример отношения, называемого SURVEY (отчет), для которого мы вполне можем
пожелать нарушить эту генеральную линию; этот пример представляет результаты
отчета по зарплате, показывающего среднюю, максимальную и минимальную зарплаты
по годам рождения для определенной категории населения (BIRTHYEAR (год рождения) служит первичным ключом).
А кортеж со значением года рождения по умолчанию ("????")
представляет людей, которые уклонились от ответа на вопрос "Когда вы
родились?".

Обратимся вновь к базе данных отделов и
служащих из главы 3. Предположим, что в компании, представленной этой базой
данных, допустимо, чтобы служащий не был причислен ни к одному из отделов.
Поэтому в кортеже ЕМР такого служащего нет настоящего номера отдела, который
может быть соответствующим значением для внешнего ключа DEPT#.
В качестве другого примера рассмотрим
самоссылающееся отношение ЕМР, которое обсуждается выше в этой главе. Каким
будет значение атрибута MGR_EMP#
для президента компании?
Для решения вопросов, подобных приведенным
в предыдущих примерах, реляционная модель традиционно разрешает появление null-значений в позициях внешних ключей.
(Заслуживает внимания, между прочим, то, что эти null-значения подходят для представления
атрибутов типа "значение не существует", а не "значение
неизвестно".) Поэтому приведенное выше определение внешнего ключа требует
некоторой небольшой доработки с учетом следующего дополнения (которое выделено жирным
шрифтом).
Пусть R2 — базовое отношение. Тогда внешний ключ, скажем, FK в отношении R2 — это подмножество множества атрибутов R2, такое что:
■
существует
базовое отношение R1 (R1 и R2 не обязательно различны) с потенциальным ключом СК;
■
всегда
каждое значение FK в
текущем значении R2 или
является null-значением, или совпадает со значением СК некоторого кортежа в текущем
значении R1.
Правило ссылочной целостности "База
данных не должна содержать никаких не соответствующих значений внешних ключей"
остается неизменным, но значение выражения "не соответствующих значений
внешних ключей" расширено до ссылки к не-null-значению внешнего ключа, для которого не
существует адекватного значения соответствующего потенциального ключа в
соответствующем целевом отношении.
Рассмотрим детальнее.
1.
Теперь есть
другое правило внешнего ключа (в дополнение к правилам удаления и обновления,
рассмотренным выше в этой главе) для обсуждения, а именно правило null-значений, т.е. для каждого внешнего ключа
разработчик базы данных должен решить, может или нет внешний ключ использовать null-значения. Необходимо расширить синтаксис
определения внешнего ключа следующим образом:

(где параметр null-option может принимать значения ALLOWED (разрешено) или NOT ALLOWED (не разрешено)), чтобы позволить
проектировщику записать свое решение.
2.
Если данный
внешний ключ FK составной
и null-значения
действительно разрешены, то в этом случае существуют разные мнения относительно
того, можно ли разрешать данному значению ключа FK иметь некоторые компоненты равными null, а остальные не равными, или необходимо
настаивать на том, чтобы каждое значение составного ключа FK было полностью null-значением или полностью
не-пи11-значением. В этой дискуссии мы занимаем вторую (более простую) позицию.
(См. [5.4, 5.7], где детально рассматривается эта дискуссия.)
3.
И вновь
обратимся к вопросу о том, что должно случиться при попытке удалить целевой
объект, на который ссылается внешний ключ: например, попытке удалить кортеж
поставщика, для которого существует, по крайней мере, одна соответствующая
поставка. Для определенности давайте еще раз рассмотрим этот случай подробно.
Если для рассматриваемого внешнего ключа, например SP.S#, null-значения разрешены, то имеется и другая возможность для правила
удаления (т.е. другое возможное значение в синтаксисе для параметра option), а именно NULLIFIES (аннулировать).
•
В
соответствии с опцией NULLIFIES внешний ключ устанавливается равным null для всех соответствующих поставок, а
кортеж поставщика затем удаляется.
4.
Также еще
раз вернемся к вопросу о том, что должно случиться при попытке обновления
потенциального ключа, на который ссылается внешний ключ: например, попытке
обновить номер поставщика, для которого существует, по крайней мере, одна
соответствующая поставка: И этот случай давайте рассмотрим еще раз подробно.
Если для рассматриваемого внешнего ключа, например SP.S#, null-значения разрешены, то имеется и другая возможность для правила
обновления (т.е. другое возможное значение в синтаксисе для параметра option), а именно NULLIFIES.
•
В
соответствии с опцией NULLIFIES внешний ключ устанавливается равным null для всех соответствующих поставок, а
кортеж поставщика затем обновляется.
Наше общее мнение состоит в том, что null-значения не желательны и не стоит
разрушать всю реляционную модель просто из-за того, что иногда соответствующий
целевой кортеж не существует для некоторого определенного внешнего ключа (т.е.
для некоторого внешнего ключа неизбежно должны быть разрешены null-значения). (В следующих главах мы
объясним, почему, по нашему мнению, null-значения "разрушают модель".)
Поэтому предположим, как предлагалось
ранее, что мы решили отвергнуть идею null-значений, а вместо этого используем значения по
умолчанию для представления отсутствующей информации. Тогда, очевидно,
можно создать "целевой кортеж по умолчанию" со значениями по
умолчанию для соответствующего потенциального ключа и при необходимости
использовать эти же значения (вместо null-значений) для соответствующих внешних ключей. Этот подход
не очень элегантен, но он имеет существенное преимущество, поскольку не
разрушает логические основы реляционной модели. Поэтому до следующего
специального указания мы будем игнорировать все аспекты поддержки null-значений, в частности для определенного
внешнего ключа не будем допускать возможность иметь null-значения.