Мартин Грубер - Понимание SQL
SQL поддерживает справочную целостность с ограничением FOREIGN KEY.
Хотя ограничение FOREIGN KEY - это новая особенность в SQL, оно еще не обеспечивает его универсальности. Кроме того, некоторые его реализации, более сложны чем другие. Эта функция должна ограничивать значения которые вы можете ввести в вашу базу данных чтобы заставить внешний ключ и родительский ключ соответствовать принципу справочной целостности. Одно из действий ограничения Внешнего Ключа - это отбрасывание значений для полей ограниченных как внешний ключ который еще не представлен в родительском ключе. Это ограничение также воздействует на вашу способность изменять или удалять значения родительского ключа (мы будем обсуждать это позже в этой главе ).
КАК МОЖНО ПОЛЯ ПРЕДСТАВИТЬ В КАЧЕСТВЕ ВНЕШНИХ КЛЮЧЕЙВы используете ограничение FOREIGN KEY в команде CREATE TABLE (или ALTER TABLE ), которая содержит поле которое вы хотите обьявить внешним ключом. Вы даете имя родительскому ключу на которое вы будете ссылаться внутри ограничения FOREIGN KEY. Помещение этого ограничения в команду - такое же что в для других ограничений обсужденных в предыдущей главе.
{}
Рисунок 19.1: Внешний Ключ таблицы Заказчиков с родительским ключом
Подобно большинству ограничений, оно может быть ограничением таблицы или столбца, в форме таблицы позволяющей использовать многочисленые поля как один внешний ключ.
ВНЕШНИЙ КЛЮЧ КАК ОГРАНИЧЕНИЕ ТАБЛИЦЫСинтаксис ограничения таблицы FOREIGN KEY:
FOREIGN KEY <column list> REFERENCES
<pktable> [ <column list> ]
Первый список столбцов - это список из одного или более столбцов таблицы, которые отделены запятыми и будут созданы или изменены этой командой. Pktable - это таблица содержащая родительский ключ. Она может быть таблицей, которая создается или изменяется текущей командой.
Второй список столбцов - это список столбцов которые будут составлять родительский ключ. Списки двух столбцов должны быть совместимы, т.е.:
* Они должны иметь одинаковое число столбцов.
* В данной последовательности, первый, второй, третий, и т.д., столбцы списка столбцов внешнего ключа, должны иметь одинаковые типы данных и размеры, что и первый, второй, третий, и т.д., столбцы списка столбцов родительского ключа. Столбцы в списках обоих столбцов не должны иметь одинаковых имен, хотя мы и использовали такой способ в наших примерах чтобы делать связь более понятной.
Создадим таблицу Заказчиков с полем snum определенным в качестве внешнего ключа ссылающегося на таблицу Продавцов:
CREATE TABLE Customers
( cnum integer NOT NULL PRIMARY KEY
cname char(10),
city char(10),
snum integer,
FOREIGN KEY (snum) REFERENCES Salespeople
( snum );
Имейте в виду, что при использовании ALTER TABLE вместо CREATE TABLE, для применения ограничения FOREIGN KEY, значения которые Вы указываете во внешнем ключе и родительском ключе, должны быть в состоянии справочной целостности. Иначе команда будет отклонена. Хотя ALTER TABLE очень полезна из-за ее удобства, вы должны будете в вашей системе, по возможности каждый раз, сначала формировать структурные принципы, типа справочной целостности.
ВНЕШНИЙ КЛЮЧ КАК ОГРАНИЧЕНИЕ СТОЛБЦОВВариант ограничения столбца ограничением FOREIGN KEY - по другому называется - ссылочное ограничение (REFERENCES), так как он фактически не содержит в себе слов FOREIGN KEY, а просто использует слово REFERENCES, и далее имя родительского ключа, подобно этому:
CREATE TABLE Customers
( cnum integer NOT NULL PRIMARY KEY,
cname char(10),
city char(10),
snum integer REFERENCES Salespeople (snum));
Вышеупомянутое определяет Customers.snum как внешний ключ у которого родительский ключ - это Salespeople.snum. Это эквивалентно такому ограничению таблицы:
FOREIGN KEY (snum) REGERENCES Salespeople (snum)
НЕ УКАЗЫВАТЬ СПИСОК СТОЛБЦОВ ПЕРВИЧНЫХ КЛЮЧЕЙИспользуя ограничение FOREIGN KEY таблицы или столбца, вы можете не указывать список столбцов родительского ключа если родительский ключ имеет ограничение PRIMARY KEY. Естественно, в случае ключей со многими полями, порядок столбцов во внешних и первичных ключах должен совпадать, и, в любом случае, принцип совместимости между двумя ключами все еще применим. Например, если мы поместили ограничение PRIMARY KEY в поле snum таблицы Продавцов, мы могли бы использовать его как внешний ключ в таблице Заказчиков (подобно предыдущему примеру) в этой команде:
CREATE TABLE Customers
( cnum integer NOT NULL PRIMARY KEY,
cname char(10),
city char(10),
snum integer REFERENCES Salespeople);
Это средство встраивалось в язык, чтобы поощрять вас использовать первичные ключи в качестве родительских ключей.
КАК СПРАВОЧНАЯ ЦЕЛОСТНОСТЬ ОГРАНИЧИВАЕТ ЗНАЧЕНИЯ РОДИТЕЛЬСКОГО КЛЮЧАПоддержание справочной целостности требует некоторых ограничений на значения, которые могут быть представлены в полях, обьявленных как внешний ключ и родительский ключ. Родительский ключ должен быть структурен, чтобы гарантировать, что каждое значение внешнего ключа будет соответствовать одной указанной строке. Это означает, что он (ключ) должен быть уникальным и не содержать никаких пустых значений(NULL).
Этого не достаточно для родительского ключа в случае выполнения такого требования как при объявлении внешнего ключа. SQL должен быть уверен что двойные значения или пустые значения (NULL) не были введены в родительский ключ. Следовательно вы должны убедиться, что все поля, которые используются как родительские ключи, имеют или ограничение PRIMARY KEY или ограничение UNIQUE, наподобии ограничения NOT NULL.
ПЕРВИЧНЫЙ КЛЮЧ КАК УНИКАЛЬНЫЙ ВНЕШНИЙ КЛЮЧСсылка ваших внешних ключей только на первичные ключи, как мы это делали в типовых таблицах, - хорошая стратегия. Когда вы используете внешние ключи, вы связываете их не просто с родительскими ключами на которые они ссылаются; вы связываете их с определенной строкой таблицы где этот родительский ключ будет найден. Сам по себе родительский ключ не обеспечивает никакой информации которая бы не была уже представлена во внешнем ключе. Смысл, например, поля snum как внешнего ключа в таблице Заказчиков - это связь которую он обеспечивает, не к значению поля snum на которое он ссылается, а к другой информации в таблице Продавцов, такой например как, имена продавцов, их местоположение, и так далее. Внешний ключ - это не просто связь между двумя идентичными значениями; это - связь, с помощью этих двух значений, между двумя строками таблицы указанной в запросе.
Это поле snum может использоваться чтобы связывать любую информацию в строке из таблицы Заказчиков со ссылочной строкой из таблицы Продавцов - например чтобы узнать - живут ли они в том же самом городе, кто имеет более длинное имя, имеет ли продавец кроме данного заказчика каких-то других заказчиков, и так далее.
Так как цель первичного ключа состоит в том, чтобы идентифицировать уникальность строки, это более логичный и менее неоднозначный выбор для внешнего ключа. Для любого внешнего ключа который использует уникальный ключ как родительский ключ, вы должны создать внешний ключ который бы использовал первичный ключ той же самой таблицы для того же самого действия. Внешний ключ который не имеет никакой другой цели кроме связывания строк, напоминает первичный ключ используемый исключительно для идентификации строк, и является хорошим средством сохранить структуру вашей базы данных ясной и простой, и - следовательно создающей меньше трудностей.
ОГРАНИЧЕНИЯ ВНЕШНЕГО КЛЮЧАВнешний ключ, в частности, может содержать только те значения которые фактически представлены в родительском ключе или пустые(NULL). Попытка ввести другие значения в этот ключ будет отклонена.
Вы можете обьявить внешний ключ как NOT NULL, но это необязательно, и в большинстве случаев, нежелательно. Например, предположим, что вы вводите заказчика не зная заранее, к какому продавцу он будет назначен. Лучший выход в этой ситуации, будет если использовать значение NOT NULL, которое должно быть изменено позже на конкретное значение.
ЧТО СЛУЧИТСЯ, ЕСЛИ ВЫ ВЫПОЛНИТЕ КОМАНДУ МОДИФИКАЦИИ
Давайте условимся, что все внешние ключи созданые в наших таблицах примеров, обьявлены и предписаны с ограничениями внешнего ключа, следующим образом:
CREATE TABLE Salespeople
(snum integer NOT NULL PRIMARY KEY,
sname char(10) NOT NULL,
city char(10),
comm decimal);
CREATE TABLE Customers
(cnum integer NOT NULL PRIMARY KEY,
cname char(10) NOT NULL,
city char(10),
rating integer,
snum integer,
FOREIGN KEY (snum) REFERENCES Salespeople,
UNIQUE (cnum, snum) ;
CREATE TABLE Orders
(cnum integer NOT NULL PRIMARY KEY,
amt decimal,
odate date NOT NULL,
cnum integer NOT NULL
snum integer NOT NULL
FOREIGN KEY (cnum, snum) REFERENCES
CUSTOMERS (cnum, snum);
ВКЛЮЧЕНИЕ ОПИСАНИЙ ТАБЛИЦЫ
Имеется несколько атрибутов таких определений о которых нужно поговорить. Причина по которой мы решили сделать поля cnum и snum в таблице Порядков, единым внешним ключом - это гарантия того, что для каждого заказчика содержащегося в порядках, продавец кредитующий этот порядок - тот же что и указаный в таблице Заказчиков. Чтобы создать такой внешний ключ, мы были бы должны поместить ограничение таблицы UNIQUE в два поля таблицы Заказчиков, даже если оно необязательно для самой этой таблицы. Пока поле cnum в этой таблица имеет ограничение PRIMARY KEY, оно будет уникально в любом случае, и следовательно невозможно получить еще одну комбинацию поля cnum с каким-то другим полем.