Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Основное / Письменные лекции по дисциплине «Базы данных».docx
Скачиваний:
89
Добавлен:
29.11.2021
Размер:
713.33 Кб
Скачать

5.2. Внешний ключ

Внешний ключ — (в SQL-серверах баз данных) поле в таблице, ссылающееся на поле другой таблицы. Поле, на которое оно ссылается, называется родительским или первичным ключом. Таблицу, которая имеет внешний ключ (ссылку на запись другой таблицы) нередко называют дочерней, а таблицу с родительским ключом — родительской.

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

5.2.1. Условия обеспечения целостности данных при помощи внешнего ключа

1. Для использования ограничений внешнего ключа типы обоих таблиц должны быть InnoDB.

2. Типы родительского и дочернего полей должны быть абсолютно идентичными.

3. Связь по внешнему ключу опирается на индексы, поэтому и родительское, и дочернее поля должны содержать индексы.

4. Связь по внешнему ключу должна опираться на поле с ограничениями в родительской таблице, т. е. это поле должно содержать ограничения PRIMARY KEY или UNIQUE.

5.2.2. Практический пример

Теперь мы можем создать 2 таблицы с использованием ограничения по внешнему ключу.

Создаем таблицу городов:

CREATE TABLE country

(

country_id TINYINT UNSIGNED AUTO_INCREMENT NOT NULL,

country_name VARCHAR(50) NOT NULL,

PRIMARY KEY (country_id)

) ENGINE=InnoDB;

Создаем таблицу (справочник) стран:

CREATE TABLE city

(

city_id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL,

city_name VARCHAR(50) NOT NULL,

country_id TINYINT UNSIGNED NOT NULL,

PRIMARY KEY (city_id),

INDEX ixCity (country_id),

CONSTRAINT country_city FOREIGN KEY (country_id) REFERENCES country (country_id)

) ENGINE=InnoDB;

Теперь давайте разберем указанные правила с учетом запросов. Поле с внешним ключом — это «city.country_id» (для того, чтобы не запутаться, перед названием поля мы указали через точку имя таблицы). Родительское поле (на которое ссылается внешний ключ) — это «country.country_id».

1. Для использования ограничений внешнего ключа типы обоих таблиц должны быть InnoDB.

Как видим, для обеих таблиц указан одинаковый тип — «ENGINE=InnoDB».

2. Типы родительского и дочернего полей должны быть абсолютно идентичными.

Это правило также выполняется. Тип дочернего поля «city.country_id» — «TINYINT UNSIGNED». Тип родителя «country.country_id» — также «TINYINT UNSIGNED».

3. Связь по внешнему ключу опирается на индексы, поэтому и родительское, и дочернее поля должны содержать индексы. Здесь также все ок. Дочернее поле мы индексируем, добавляя индекс в запросе — «INDEX ixCity (country_id)». Родитель индексируется автоматически. Дело в том, что для родителя мы имеем PRIMARY KEY, что как раз и предусматривает автоматический индекс для него.

4. Связь по внешнему ключу должна опираться на поле с ограничениями в родительской таблице, т. е. это поле должно содержать ограничения PRIMARY KEY или UNIQUE. И здесь все выполняется: «country.country_id» — «PRIMARY KEY (country_id)».

Отлично! Таблицы созданы и связь установлена. Теперь мы не сможем добавить город с идентификатором страны, которая не представлена в справочнике. Кстати, существует и обратная зависимость. По умолчанию мы не сможем также удалить и страну из справочника, если для нее в дочерней таблице есть города, что, в принципе, логично.

Но мы можем улучшить эту связь и сделать так, чтобы если мы что-то меняем в справочнике, то эти изменения касались также дочерней таблицы. Для этого после объявления ограничения по внешнему ключу мы можем записать выражения «ON DELETE CASCADE ON UPDATE CASCADE». По умолчанию значения этих выражений указаны «ON DELETE RESTRICT ON UPDATE RESTRICT», т. е. запрет. Таким образом, наш запрос станет таким:

CREATE TABLE city

(

city_id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL,

city_name VARCHAR(50) NOT NULL,

country_id TINYINT UNSIGNED NOT NULL,

PRIMARY KEY (city_id),

INDEX ixCity (country_id),

CONSTRAINT country_city FOREIGN KEY (country_id) REFERENCES country (country_id)

ON DELETE CASCADE ON UPDATE CASCADE

) ENGINE=InnoDB;

Теперь, если мы удалим из справочника страну, то из дочерней таблицы без всяких дополнительных запросов будут удалены все города этой страны. Удобно, не правда ли? И не нарушается целостность данных.