Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
15
Добавлен:
15.04.2015
Размер:
104 Кб
Скачать

10.Внешние ключи. Определение и свойства. Синтаксис для указания внешнего ключа. Ссылочная целостность Правила внешних ключей. Расширенный синтаксис задания внеш него ключа NULL- значения. Правило целостности объектов.

Внешние ключи - это как раз то, что делает реляционные базы “реляционными” (от relation(англ.)- отношение, связь). Это как раз те связующие цепочки, которые связывают таблицы между собой. Они позволяют вам разместить “покупателей” в одной таблице, “заказы” в другой, а товары из этих заказов, в третьей, таким образом в базе минимизируется избыточность данных. Чем меньше избыточных данных - тем больше у вас шансов сохранить целостность данных (две или более противоречащие друг-другу записи - это всегда плохо).

На данный момент, у нас есть защита целостности данных на случай каких-либо манипуляций с таблицами-потомками, но что если внести изменения в родительскую таблицу? Как нам быть уверенными, что таблицы-потомки в курсе всех изменений в родительской таблице?

MySQL позволяет нам контролировать таблицы-потомки во время обновления или удаления данных в родительской таблице с помощью подвыражений: ON UPDATE и ON DELETE. MySQL поддерживает 5 действий, которые можно использовать в выражениях ON UPDATE и/или ON DELETE.

  • CASCADE: если связанная запись родительской таблицы обновлена или удалена, и мы хотим чтобы соответствующие записи в таблицах-потомках также были обновлены или удалены. Что происходит с записью в родительской таблице, тоже самое произойдет с записью в дочерних таблицах. Однако не забывайте, что здесь можно легко попасться в ловушку бесконечного цикла.

  • SET NULL:если запись в родительской таблице обновлена или удалена, а мы хоти чтобы в дочерней таблице некоторым занчениям было присвоено NULL (конечно если поле таблицы это позволяет)

  • NO ACTION: смотри RESTRICT

  • RESTRICT:если связанные записи родительской таблицы обновляются или удаляются со значениями которые уже/еще содержатся в соответствующих записях дочерней таблицы, то база данных не позволит изменять записи в родительской таблице. Обе команды NO ACTION и RESTRICT эквивалентны отсутствию подвыражений ON UPDATE or ON DELETE для внешних ключей.

  • SET DEFAULT:На данный момент эта команда распознается парсером, но движок InnoDB никак на нее не реагирует.

Для моей базы данных из примера, я решил, что для внешних ключей из таблицы invoice, UPDATE будут выполняться каскадно для дочерних таблиц, а удаление будет запрещено. Таким образом, любые изменения в таблицах usr и product автоматически отразятся в таблице invoice, но если товар заказан или если у пользователя есть счет - они не могут быть удалены.

Ниже представлен новый вариант запроса CREATE для таблицы invoice с внешними ключами и выражениями ON UPDATE и ON DELETE

  1. CREATE TABLE invoice (

  2.         inv_id  int AUTO_INCREMENT NOT NULL,

  3.         usr_id  int NOT NULL,

  4.         prod_id  int NOT NULL,

  5.         quantity int NOT NULL,

  6.         PRIMARY KEY(inv_id),

  7.         FOREIGN KEY (usr_id) REFERENCES usr(usr_id)

  8.           ON UPDATE CASCADE

  9.           ON DELETE RESTRICT,

  10.         FOREIGN KEY (prod_id) REFERENCES product(prod_id)

  11.           ON UPDATE CASCADE

  12.           ON DELETE RESTRICT

  13.       ) ENGINE=InnoDB CHARACTER SET=UTF8;

Ссы́лочная це́лостность (англ. referential integrity) — необходимое качество реляционной базы данных, заключающееся в отсутствии в любом её отношении внешних ключей, ссылающихся на несуществующие кортежи.

Связи между данными, хранимыми в разных отношениях, в реляционной БД устанавливаются с помощью использования внешних ключей — для установления связи между кортежем из отношения A с определённым кортежем отношения B в предусмотренные для этого атрибуты кортежа отношения A записывается значение первичного ключа (а в общем случае значение потенциального ключа) целевого кортежа отношения B. Таким образом, всегда имеется возможность выполнить две операции:

  • определить, с каким кортежем в отношении B связан определённый кортеж отношения A;

  • найти все кортежи отношения A, имеющие связи с определённым кортежем отношения B.

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

Дана пара отношений A и B, связанных внешним ключом. Первичный ключ отношения B — атрибут B.key. Внешний ключ отношения A, ссылающийся на B — атрибут A.b. Ссылочная целостность для пары отношений A и B имеет место тогда, когда выполняется условие: для каждого кортежа отношения A существует соответствующий кортеж отношения B, то есть кортеж, у которого (B.key = A.b).

База данных обладает свойством ссылочной целостности, когда для любой пары связанных внешним ключом отношений в ней условие ссылочной целостности выполняется.

Если вышеприведённое условие не выполняется, говорят, что в базе данных нарушена ссылочная целостность. Такая БД не может нормально эксплуатироваться, так как в ней разорваны логические связи между зависимыми друг от друга фактами. Непосредственным результатом нарушения ссылочной целостности становится то, что корректным запросом не всегда удаётся получить корректный результат.

Пример:

Так, в примере реляционная БД, состоящая из таблиц Address и Street, обеспечивает хранение адресов. При этом основная таблица, — Address, — содержит непосредственно номер дома и квартиры, а вместо имени улицы в поле Street имеет внешний ключ, ссылающийся на таблицу Street — справочник улиц. Очевидно, что полноценный адрес должен быть представлен двумя связанными записями в обеих названных таблицах, что технически выражается в условии: для любой записи таблицы Address в таблице Street должна существовать соответствующая запись, то есть запись со (Street.Key = Address.Street). Чтобы получить список полных адресов из таблиц такой структуры, когда в них соблюдается ссылочная целостность, достаточно применить к данным таблицам SQL-запрос:

select *

from Address, Street

where

Address.Street = Street.Key

В данном примере, однако, ссылочная целостность нарушена. Две записи таблицы Address (Key = 887 и Key = 994) имеют в поле Street так называемые «висящие» ссылки — значения, которым не соответствуют записи в таблице Street (эти ссылки показаны красным цветом). Из-за этого результат вышеприведённого запроса не будет содержать этих двух записей — для них условие запроса не выполнится. И ещё одна запись не будет выбрана вышеприведённым запросом — запись таблицы Address с (Key = 85). Это вариант намеренного (и, в некоторых случаях, легального) нарушения ссылочной целостности — в поле внешнего ключа записан NULL (показано голубым цветом). Чтобы получить список всех адресов, даже тех, у которых не указана улица, необходимо использовать открытое соединение, в одном из вариантов синтаксиса записываемое так:

select *

from Address left outer join Street on (Address.Street = Street.Key)

Если же требуется получить список, не включающий записи с «висящими» ссылками, то придётся усложнить запрос:

select *

from Address left outer join Street on ((Address.Street = Street.Key) or (Address.Street is null))

Правила внешних ключей

Для обеспечения ссылочной целостности или, как иногда говорят, для поддержки внешних ключей, у пользователя базы данных должна быть возможность определить набор операций по связи между Primary Key и Foreign Key, которые ему разрешены и которые ему запрещены. Прежде всего такая ситуация возникает, когда необходимо выполнить операцию Delete (что делать, если в главной таблице удаляется родительская запись).

В общем случае тут могут быть следующие операции:

1. Restrict – запретить удаление из главной, если есть подчиненные.

2. Cascade – каскадно удалить все подчиненные записи.

3. Set Null – установить значение внешних ключей подчиненных записей в нулевое значение (Null – значение).

4. Set Default – установить значение вешних ключей в предопределенное, начальное значение.

5. No Action – ничего не делать.

В Desktop по умолчанию No Action. Если рассматривать простую таблицу – родители и дети – «Если умирает родитель, это не означает, что детей тоже надо убивать… Запретить умирать тоже нельзя». Какое значение установить в подчиненных записях –«детях» – в каждом контексте решает сам пользователь(Set Null и т.д.). В данном случае операции Restrict и Cascade применять нельзя.

Вторая операция здесь – это Update.(что делать, если мы обновляем, меняем Primary Key в главной таблице). Возникает вопрос, что делать с Foreign Key в данном случае. В общем случае, все ранее названные операции для Delete здесь тоже могут быть. Все также зависит от контекста – e.g. при смене названия улицы, необходимо обновить названия в паспортах, табличках и т.д.. Но чаще всего применяют операцию Restrict – запретить обновление.

Каждая из операций так или иначе требует определенного кода, чтобы ее выполнить. К исключениям можно отнести лишь No Action. Во всех остальных случаях необходимо наличие кода. На практике это решается, условно говоря, одним способом, но двумя реализациями. Используется триггеры, являясь процедурой, она запускается на сервере баз данных, т.е. пользователь сам такой триггер явно запустить не может. Такого рода триггеры могут быть созданы на три операции – Insert (добавление), Delete,Update. Две реализации триггеров:

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

2. В простейшем случае, без учета всех тонкостей, СУБД сама может создать стандартный триггер, который реализует простое каскадное обновление или удаление и т.д. Как правило, он откомпилирован и посмотреть код такого триггера невозможно.

Предикат null

Предикат null описывается синтаксическим правилом

<null predicate> ::=

<column specification> IS [NOT] NULL

Этот предикат всегда принимает значения true или false. При этом значение "x IS NULL" равно true тогда и только тогда, когда значение х не определено. Значение предиката "x NOT IS NULL" равно значению "NOT x IS NULL".

Проверка на null

В свете того, какой беспорядок может навести NULL, вы часто захотите узнать, является ли что-либо NULL прежде, чем вы будете использовать это в выражении. Для некоторых очевидная проверка должна выглядеть так:

if (A = NULL) then...

И в самом деле, есть системы управления базами данных, которые поддерживают такой синтаксис проверки на NULL. Но стандарт SQL не допускает этого, не допускает этого и СУБД Firebird. В версиях до 2.0 такой синтаксис был даже недопустим. С версии 2.0 он разрешается, но сравнение всегда вернет NULL, независимо от состояния и значения A. Поэтому такой тест на NULL является бесполезным - нам нужен явный результат true или false.

Корректный способ проверки на NULL такой:

...is null / ...is not null

Эта проверка всегда вернет true или false - и никакой неразберихи. Примеры:

  • if (MyField is null) then...

  • select * from Pupils where PhoneNumber is not null

  • select * from Pupils where not (PhoneNumber is null)

  • /* делает то же самое, что и предыдущий пример */

  • update Numbers set Total = A + B + C where A + B + C is not null

Можно сказать, что в то время как равенство «=» (когда используется как оператор равенства) может сравнивать значения, «is» проверяет состояние.

Соседние файлы в папке 8. Антипов