Итак, все пройденные нами понятия, а именно диаграммы и их виды, кратности и виды связей, а также виды миграции ключей, теперь помогут нам в прохождении материала о тех же связях, но уже между конкретными классами сущностей.
Среди них, как мы увидим, тоже бывают связи различных видов.
Первым видом связи классов сущностей между собой, который мы рассмотрим, является так называемая иерархическая рекурсивная связь.
Вообще рекурсия (или рекурсивная связь) – это связь класса сущностей с самим собой.
Иногда по аналогии с жизненными ситуациями такую связь еще называют «рыболовный крючок».
Иерархической рекурсивной связью (или просто иерархической рекурсией) называется любая рекурсивная связь типа «не более одного ко многим».
Иерархическая рекурсия чаще всего используется для того, чтобы хранить данные древовидной структуры.
При задании иерархической рекурсивной связи первичный ключ родительского класса сущностей (который в данном конкретном случае одновременно выступает и в роли дочернего класса сущностей) должен мигрировать в качестве внешнего ключа в состав обязательно неключевых атрибутов того же класса сущностей. Все это необходимо для поддержания логической целостности самого понятия «иерархическая рекурсия».
Таким образом, с учетом всего вышесказанного, можно сделать вывод, что иерархическая рекурсивная связь может быть только не обязательно не идентифицирующей и никакой другой, потому что в случае использования любого другого вида связи, Null-значения для внешнего ключа были бы недопустимы и рекурсия была бы бесконечной.
Важно также помнить, что атрибуты не могут появляться дважды в одном и том же классе сущностей под одним и тем же именем. Поэтому атрибуты мигрировавшего ключа обязательно должны получить так называемое имя роли.
Таким образом, в иерархической рекурсивной связи атрибуты узла расширяются внешним ключом, представляющим необязательную ссылку на первичный ключ узла, являющийся его непосредственным предком.
Построим презентационную и ключевую диаграммы, реализующую иерархическую рекурсию в реляционной модели данных, и приведем пример табличной формы.
Сначала составим презентационную диаграмму:
Теперь построим более подробную – ключевую диаграмму:
Рассмотрим пример, наглядно иллюстрирующий такой вид связи, как иерархическая рекурсивная связь. Пусть нам дан следующий класс сущностей, состоящий, как и предыдущий пример, из атрибутов «Код Предка» и «Код Узла». Сначала покажем табличную форму представления этого класса сущности:
А теперь построим диаграмму, представляющую этот класс сущностей. Для этого выделим из таблицы все необходимые для этого сведения: предка у узла с кодом «единица» не существует или не определен, из этого делаем вывод, что узел «единица» является вершиной. Этот же самый узел «единица» является предком для узлов с кодом «два» и «три». В свою очередь, у узла с кодом «два» имеются два потомка: узел с кодом «четыре» и узел с кодом «пять». А у узла с кодом «три» – только один потомок – узел с кодом «шесть».
Итак, с учетом всего вышесказанного построим древовидную структуру, отражающую информацию о данных, заложенную в предыдущей таблице:
Итак, мы увидели, что представлять древовидные структуры действительно удобно при помощи иерархической рекурсивной связи.
Сетевая рекурсивная связь классов сущностей между собой является как бы многомерным аналогом уже пройденной нами иерархической рекурсивной связи.
Только если иерархическая рекурсия определялась как рекурсивная связь типа «не более одного ко многим», то сетевая рекурсия представляет собой такую же рекурсивную связь, только уже типа «многие ко многим». Из-за того что в этой связи с каждой стороны участвует много классов сущностей, ее и называют сетевой.
Как уже можно догадаться по аналогии с рекурсией иерархической, связи вида сетевой рекурсии предназначены для представления графовых структур данных (тогда как иерархические связи применяются, как мы помним, исключительно для реализации древовидных структур).
Но, так как в связи вида сетевой рекурсии заданы связи типа именно «многие ко многим», без их дополнительной детализации не обойтись. Поэтому для уточнения всех имеющихся в схеме связей типа «многие ко многим» становится необходимым создать новый самостоятельный класс сущностей, содержащий все ссылки на предка или потомка связи «Предок – Потомок». Такой класс в общем случае называется классом ассоциативных сущностей.
В нашем частном случае (в базах данных, подлежащих рассмотрению в нашем курсе) ассоциативная сущность не имеет собственных дополнительных атрибутов и называется именующей, так как именует связи «Предок – Потомок» путем ссылок на них. Таким образом, первичный ключ класса сущностей, представляющего узлы сети, должен дважды мигрировать в классы ассоциативных сущностей. В этом классе мигрировавшие ключи в совокупности должны образовывать составной первичный ключ.
Из всего вышесказанного можно сделать вывод, что устанавливающие связи при использовании сетевой рекурсии должны быть не полностью идентифицирующими и никакими другими.
Так же как и при использовании иерархической рекурсивной связи, при применении в качестве связи сетевой рекурсии ни один атрибут не может появляться дважды в одном классе сущностей под одним и тем же именем. Поэтому, как и в прошлый раз, специально оговаривается, что все атрибуты мигрирующего ключа обязательно должны получить имя роли.
Для иллюстрирования работы сетевой рекурсивной связи, построим презентационную и ключевую диаграммы, реализующие сетевую рекурсию в реляционной модели данных.
Сначала представим презентационную диаграмму:
А теперь построим более подробную ключевую диаграмму:
Что мы здесь видим? А видим мы, что обе связи, имеющиеся в данной ключевой диаграмме, являются связями вида «многие к одному». Причем кратность «0… ∞ » или кратность «много» стоит на конце связи, обращенной к именующему классу сущностей. Действительно, ведь ссылок много, а ссылаются они все на какой-то один код узла, являющийся первичным ключом класса сущностей «Узлы».
И, наконец, рассмотрим пример, иллюстрирующий работу такого вида связи классом сущностей как сетевая рекурсия. Пусть нам дано табличное представление некоторого класса сущностей, а также именующий класс сущностей, содержащий информацию о ссылках. Приведем эти таблицы.
Узлы:
Ссылки:
Действительно, вышеприведенное представление исчерпывающе: оно дает всю необходимую информацию для того, чтобы без труда воспроизвести зашифрованную здесь графовую структуру. Например, мы без всяких препятствий можем увидеть, что у узла с кодом «один» имеются три потомка соответственно с кодами «два», «три» и «четыре». Также мы видим, что у узлов с кодами «два» и «три» потомков не имеется вообще, а у узла с кодом «четыре» имеются (также как и у узла «один») три потомка с кодами «один», «два» и «три».
Изобразим граф, заданный классами сущностей, приведенными выше:
Итак, только что построенный нами граф и является теми данными, для связывания классов сущностей которых и использовалась связь вида сетевой рекурсии.
Из всех видов связей, входящих в рассмотрение нашего конкретного курса лекций, рекурсивными связями являются только две. Мы их уже успели рассмотреть, это соответственно иерархическая и сетевая рекурсивные связи.
Все остальные виды связей, которые нам предстоит рассмотреть, не являются рекурсивными, а представляют собой, как правило, связь нескольких родительских и нескольких дочерних классов сущностей. Причем, как можно догадаться, родительские и дочерние классы сущностей теперь уже никогда не будут совпадать (действительно, ведь речь уже не идет о рекурсии).
Связь, о которой пойдет речь в этом параграфе лекции, называется ассоциацией и относится как раз к нерекурсивному виду связей.
Итак, связь, называемая ассоциацией, реализуется как взаимосвязь между несколькими родительскими классами сущностей и одним дочерним классом сущностей. И при этом, что любопытно, эта взаимосвязь описывается связями различных типов.
Также стоит отметить, что родительский класс сущностей при ассоциации может быть и один, как в сетевой рекурсии, но даже в такой ситуации число связей, идущих от дочернего класса сущностей, должно быть не менее двух.
Интересно, что при ассоциации, так же как и при сетевой рекурсии, существуют специальные виды классов сущностей. Примером такого класса является дочерний класс сущностей. Ведь в общем случае в ассоциации дочерний класс сущностей называется классом ассоциативных сущностей. В частном случае, когда класс ассоциативных сущностей не имеет собственных дополнительных атрибутов и содержит только атрибуты, мигрирующие вместе с первичными ключами из родительских классов сущностей, такой класс называется классом именующих сущностей. Как можно обратить внимание, при этом прослеживается почти абсолютная аналогия с понятием ассоциативных и именующих сущностей в сетевой рекурсивной связи.
Чаще всего ассоциация используется для детализации (разрешения) связей вида «многие ко многим».
Проиллюстрируем это утверждение.
Пусть, например, нам дана следующая презентационная диаграмма, описывающая схему приема некоторого врача в некой больнице:
Эта диаграмма буквально означает, что в больнице имеется много врачей и много пациентов, и больше никак отношения и соответствия между врачами и пациентами не отражено. Таким образом, разумеется, что с такой базой данных в администрации больницы никогда не было бы понятно, как проводить приемы у различных врачей различных пациентов. Ясно, что использованные здесь связи типа «многие ко многим» просто необходимо детализировать, чтобы конкретизировать отношения между различными врачами и пациентами, другими словами, чтобы рационально организовать расписание приемов всех имеющихся в больнице врачей и их пациентов.
А теперь построим более подробную ключевую диаграмму, в которой мы уже детализируем все имеющиеся связи «многие ко многим». Для этого мы соответственно введем новый класс сущностей, назовем его «Прием», который будет выступать в роли класса ассоциативных сущностей (позже мы посмотрим, почему именно это будет классом ассоциативных сущностей, а не просто классом именующих сущностей, о которых мы говорили ранее).
Итак, наша ключевая диаграмма будет выглядеть следующим образом:
Итак, теперь наглядно видно, почему новый класс «Прием» не является классом именующих сущностей. Ведь этот класс имеет свой дополнительный атрибут «Дата – Время», поэтому согласно определению нововведенный класс «Прием» и является классом ассоциативных сущностей. Этот класс «ассоциирует» классы сущностей «Врачи» и «Пациенты» друг с другом посредством времени, в которое и проводится тот или иной прием, что делает работу с такой базой данных гораздо удобнее. Таким образом, мы, введя атрибут «Дата – Время», буквально организовали так необходимое расписание работы различных врачей.
Также мы видим, что внешний первичный ключ «Код Врача» класса сущностей «Прием» ссылается на одноименный первичный ключ класса сущностей «Врачи». И аналогично внешний первичный ключ «Код Пациента» класса сущностей «Прием» ссылается на одноименный первичный ключ класса сущностей «Пациенты». В данном случае, что само собой разумеется, классы сущностей «Врачи» и «Пациенты» являются родительскими, а класс ассоциативных сущностей «Прием», в свою очередь, является единственным дочерним.
Мы видим, что теперь имеющаяся в прежней презентационной диаграмме связь типа «многие ко многим» полностью детализирована. Вместо одной связи «многие ко многим», какую мы видим в презентационной диаграмме, приведенной ранее, у нас имеется две связи типа «многие к одному». На дочернем конце первой связи стоит кратность «много», это буквально означает, что в классе сущностей «Прием» записано много врачей (все, которые есть в больнице). А на родительском конце этой связи стоит кратность «один», что это значит? А значит это, что в классе сущностей «Прием» каждый из имеющихся кодов каждого конкретного врача может встречаться неограниченно много раз. Действительно, ведь в расписании в больнице код одного и того же врача встречается много раз, в разные дни и время. А вот этот же код, но уже в классе сущностей «Врачи» может встретиться один и только один раз. Действительно, ведь в списке всех врачей больницы (а класс сущностей «Врачи» представляет собой не что иное, как такой список) код каждого конкретного врача может присутствовать только один раз.
Аналогичное происходит и со связью между родительским классом «Пациенты» и дочерним классом «Пациенты». В списке всех пациентов больницы (в классе сущностей «Пациенты») код каждого конкретного пациента может встретиться только один раз. Но зато в расписании приемов (в классе сущностей «Прием») каждый код конкретного пациента может встретиться сколь угодно много раз. Именно поэтому кратности на концах связи расставлены как раз таким образом.
В качестве примера реализации ассоциации в реляционной модели данных построим модель, описывающую график встреч заказчика с исполнителем при необязательном участии консультантов.
Не будем останавливаться на презентационной диаграмме, потому что нам необходимо рассмотреть построение диаграмм во всех подробностях, а презентационная диаграмма такой возможности предоставить не может.
Итак, построим ключевую диаграмму, отражающую суть отношений между заказчиком, исполнителем и консультантом.
Итак, начнем подробный разбор приведенной ключевой диаграммы.
Во-первых, класс «График» является классом ассоциативных сущностей, но, так же как и в прошлом примере, не является классом именующихся сущностей, ведь у него есть атрибут, не мигрирующий в него вместе с ключами, а являющийся его собственным атрибутом. Это атрибут «Дата – Время».
Во-вторых, мы видим, что атрибуты дочернего класса сущностей «График» «Код заказчика», «Код исполнителя» и «Дата – Время» образуют составной первичный ключ этого класса сущностей. Атрибут «Код консультанта» является просто внешним ключом класса сущностей «График». Обратим внимание, что этот атрибут допускает среди своих значений Null-значения, ведь по условию присутствие на встрече консультанта не обязательно.
Далее, в-третьих, заметим, что первые две связи (из трех имеющихся связей) являются не полностью идентифицирующими. Именно не полностью идентифицирующими, потому что мигрирующий ключ в обоих случаях (первичные ключи «Код заказчика» и «Код исполнителя») не полностью формирует первичный ключ класса сущностей «График». Действительно, ведь остается атрибут «Дата – Время», который также является частью составного первичного ключа.
На концах обеих этих не полностью идентифицирующих связей проставлены кратности «один» и «много». Это сделано для того, чтобы показать (как и в примере о врачах и пациентах) разницу, между упоминанием кода заказчика или исполнителя в разных классах сущностей. Действительно, в классе сущностей «График» любой код заказчика или исполнителя может встречаться сколь угодно много раз. Поэтому на этом, дочернем, конце связи стоит кратность «много». А в классе сущностей «Заказчики» или «Исполнители» каждый из кодов соответственно заказчика или исполнителя может встречаться один и только один раз, ведь эти классы сущностей являются каждый не чем иным, как полным списком всех заказчиков и исполнителей. Поэтому на этом, родительском конце связи, и стоит кратность «один».
И, наконец, заметим, что третья связь, а именно связь класса сущностей «График» с классом сущностей «Консультанты», является не обязательно не идентифицирующей.
Действительно, ведь в этом случае речь идет о переносе ключевого атрибута «Код консультанта» класса сущностей «Консультанты» в одноименный неключевой атрибут класса сущностей «График», т. е. первичный ключ класса сущностей «Консультанты» в классе сущностей «График» не идентифицирует первичного ключа уже этого класса. И, кроме того, как уже было упомянуто ранее, атрибут «Код консультанта» допускает Null-значения, поэтому здесь и используется именно не полностью не идентифицирующая связь. Таким образом, атрибут «Код консультанта» приобретает статус внешнего ключа и ничего более того.
Также обратим внимание на кратности связей, поставленных на родительском и дочернем концах этой не полностью не идентифицирующей связи. На ее родительском конце стоит кратность «не более одного». Действительно, если вспомнить определение не полностью не идентифицирующей связи, то мы поймем, что атрибуту «Код консультанта» из класса сущностей «График» не может соответствовать более одного кода консультанта из списка всех консультантов (которым является класс сущностей «Консультанты»). Да и вообще может так получиться, что ему не будет соответствовать ни одного кода консультанта (вспомним о флажке допустимости Null-значений Код консультанта: Null), ведь по условию присутствие консультанта на встрече заказчика и исполнителя, вообще говоря, не обязательно.
Очередным видом связи классов сущностей между собой, который мы рассмотрим, является связь вида обобщение. Это также нерекурсивный вид связи.
Итак, связь типа обобщение реализуется как взаимосвязь одного родительского класса сущностей с несколькими дочерними классами сущностей (в отличие от предыдущей рассмотренной связи Ассоциации, в которой речь шла о нескольких родительских классах сущностей и одним дочернем классе сущностей).
При формулировании правил представления данных при помощи связи Обобщения необходимо сразу сказать, что эта взаимосвязь одного родительского класса сущностей и нескольких дочерних классов сущностей, описывается полностью идентифицирующими связями, т. е. категориальными связями. Вспоминая определение полностью идентифицирующих связей, мы приходим к выводу, что при использовании Обобщения каждый атрибут первичного ключа родительского класса сущностей переносится в состав первичного ключа классов сущностей дочерних, т. е. атрибуты первичного мигрирующего ключа родительского класса сущностей полностью формируют первичные ключи всех дочерних классов сущностей, они их идентифицируют.
Любопытно отметить, что при Обобщении реализуется так называемая иерархия категорий или иерархия наследования.
При этом родительский класс сущностей определяет класс обобщенных сущностей, характеризующийся атрибутами, общими для сущностей всех дочерних классов или так называемых категориальных сущностей т. е. родительский класс сущностей представляет собой буквальное обобщение всех своих дочерних классов сущностей.
В качестве примера реализации обобщения в реляционной модели данных построим следующую модель. Эта модель будет основана на обобщенном понятии «Учащиеся» и будет описывать следующие категориальные понятия (т. е. будет обобщать следующие дочерние классы сущностей): «Школьники», «Студенты» и «Аспиранты».
Итак, построим ключевую диаграмму, отражающую суть взаимоотношений между родительским классом сущности и дочерними классами сущностей, описываемых связью типа Обобщение.
Итак, что же мы видим?
Во-первых, каждому из базовых отношений (или из классов сущностей, что одно и то же) «Школьники», «Студенты» и «Аспиранты» соответствуют свои собственные атрибуты, как то «Класс», «Курс» и «Год обучения». Каждый из этих атрибутов характеризует участников своего собственного класса сущностей. Еще мы видим, что первичный ключ родительского класса сущностей «Учащиеся» мигрирует в каждый дочерний класс сущностей и формирует там первичный внешний ключ. При помощи этих связей мы можем по коду любого учащегося определить его имя, фамилию и отчество, информацию о которых мы не найдем в самих соответствующих дочерних классах сущностей.
Во-вторых, так как мы говорим о полностью идентифицирующей (или категориальной) связи классов сущностей, то обратим внимание на кратности связей между родительским классом сущностей и его дочерними классами. На родительском конце каждой из этих связей стоит кратность «один», а на каждом дочернем конце связей стоит кратность «не более одного». Если вспомнить определение полностью идентифицирующей связи классов сущностей, то становится понятно, что действительно единственный в своем роде код учащегося, являющийся первичным ключом класса сущностей «Учащиеся», задает не более одного атрибута с таким кодом в каждом дочернем классе сущностей «Школьники», «Студенты» и «Аспиранты». Поэтому все связи имеют именно такие кратности.
Запишем фрагмент операторов создания базовых отношений «Школьники» и «Студенты» с определением правил поддержания ссылочной целостности типа cascade. Итак, имеем:
Create table Школьники
…
primary key (Код ученика)
foreign key (Код ученика) references Учащиеся (Код ученика)
on update cascade
on delete cascade
Create table Студенты
…
primary key (Код студента)
foreign key (Код студента) references Учащиеся (Код студента)
on update cascade
on delete cascade;
Таким образом, мы видим, что в дочернем классе сущностей (или отношений) «Школьники» задается первичный внешний ключ, ссылающийся на родительский класс сущностей (или отношение) «Учащиеся». Правило cascade поддержания ссылочной целостности определяет, что при удалении или при обновлении атрибутов родительского класса сущностей «Учащиеся» соответствующие им атрибуты дочернего отношения «Школьники» будут автоматически (каскадом) обновляться или удаляться. Аналогично при удалении или при обновлении атрибутов родительского класса сущностей «Учащиеся» соответствующие им атрибуты дочернего отношения «Студенты» также будут автоматически обновляться или удаляться.
Необходимо заметить, что здесь используется именно это правило поддержания ссылочной целостности, потому что в данном контексте (перечень учащихся) не рационально запрещать удаление и обновление информации, а также присваивать неопределенное значение вместо реальных сведений.
А теперь приведем пример классов сущностей, описанных в предыдущей диаграмме, только представленных в табличной форме. Итак, имеем следующие таблицы-отношения:
Учащиеся – родительское отношение, объединяющее в себе информацию об атрибутах всех остальных отношений:
Школьники – дочернее отношение:
Студенты – второе дочернее отношение:
Аспиранты – третье дочернее отношение:
Итак, действительно, мы видим, что в дочерних классах сущностей не прописана информация о фамилии, имени и отчестве учащихся, т. е. школьников, студентов и аспирантов. Эту информацию можно получить только посредством ссылок на родительский класс сущностей.
Также мы видим, что различные коды учащихся в классе сущностей «Учащиеся» могут соответствовать различным дочерним классам сущностей. Так, про учащегося с кодом «1» Заботина Николая в родительском отношении неизвестно ничего, кроме его имени, а всю остальную информацию (кто он, школьник, студент или аспирант) можно узнать только обратившись к соответствующему дочернему классу сущностей (определяется по коду).
Аналогичным образом необходимо работать с остальными учащимися, чьи коды указаны в родительском классе сущностей «Учащиеся».
Связь классов сущностей типа композиция, так же как и две предыдущие, не принадлежит к виду рекурсивной связи.
Композиция (или, как ее еще иногда называют, композитная агрегация) – это взаимосвязь одного родительского класса сущностей с несколькими дочерними классами сущностей, так же как и предыдущая рассмотренная нами связь. Обобщение.
Но если обобщение определялось как взаимосвязь классов сущности, описывающаяся полностью идентифицирующимися связями, то композиция, в свою очередь, описывается не полностью идентифицирующими связями, т. е. при композиции каждый атрибут первичного ключа родительского класса сущностей мигрирует в ключевой атрибут дочернего класса сущностей. И при этом атрибуты мигрирующего ключа лишь частично формируют первичный ключ дочернего класса сущностей.
Итак, при композитной агрегации (при композиции) родительский класс сущностей (или агрегат) связывается с несколькими дочерними классами сущностей (или компонентами). При этом компоненты агрегата (т. е. компоненты родительского класса сущностей) ссылаются на агрегат посредством внешнего ключа, входящего в состав первичного ключа и, следовательно, не могут существовать вне агрегата.
Вообще композитная агрегация представляет собой усиленную форму простой агрегации (о которой мы поговорим чуть дальше). Композиция (или композитная агрегация) характеризуется тем, что:
1) ссылка на агрегат участвует в идентификации компонентов;
2) эти компоненты не могут существовать вне агрегата.
Агрегация (связь, которую мы будем рассматривать дальше) с обязательно не идентифицирующими связями также не позволяет компонентам существовать вне агрегата и поэтому близка по смыслу к описанной выше реализации композитной агрегации.
Построим ключевую диаграмму, описывающую взаимосвязь между одним родительским классом сущностей и несколькими дочерними классами сущностей, т. е. описывающую связь классов сущностей типа композитной агрегации.
Пусть это будет ключевая диаграмма, изображающая состав корпусов некого учебного городка, включающего в себя корпуса, их аудитории и лифты. Итак, эта диаграмма будет иметь следующий вид:
Итак, рассмотрим только что построенную диаграмму.
Что мы в ней видим?
Во-первых, мы видим, что связь, использованная в этой композитной агрегации, действительно идентифицирующая и действительно не полностью идентифицирующая. Ведь первичный ключ родительского класса сущностей «Корпуса» участвует в формировании первичного ключа дочерних классов сущностей «Аудитории» и «Лифты», но не определяет его полностью. Первичный ключ «№ корпуса» родительского класса сущностей мигрирует во внешние первичные ключи «№ корпуса» обоих дочерних классов, но, кроме этого мигрировавшего, ключа у обоих дочерних классов сущностей существует и свой собственный первичный ключ, соответственно «№ аудитории» и «№ лифта», т. е. составные первичные ключи дочерних классов сущностей лишь частично оказываются сформированными атрибутами первичного ключа родительского класса сущностей.
Теперь разберемся с кратностями связей, соединяющих родительский и оба дочерних класса. Так как мы имеем дело с не полностью идентифицирующими связями, то кратности присутствуют такие: «один» и «много». Кратность «один» присутствует на родительском конце обеих связей и символизирует то, что в списке всех имеющихся корпусов (а класс сущностей «Корпуса» является именно таким списком) каждый номер может встретиться только один, (и не более того) раз. А, в свою очередь, среди атрибутов классов «Аудитории» и «Лифты» каждый номер корпуса может встретиться много раз, так как аудиторий (или лифтов) больше, чем корпусов, и в каждом корпусе – несколько и аудиторий, и лифтов. Таким образом, при перечислении всех аудиторий и лифтов мы неминуемо будем повторять номера корпусов.
И, наконец, как и при рассмотрении предыдущего вида связи, запишем фрагменты операторов создания базовых отношений (или, что одно и то же, классов сущностей) «Аудитории» и «Лифты», причем сделаем это с определением правил поддержания ссылочной целостности типа cascade.
Итак, этот оператор будет выглядеть следующим образом:
Create table Аудитории
…
primary key (№ корпуса, № аудитории)
foreign key (№ корпуса) references Корпуса (№ корпуса)
on update cascade
on delete cascade
Create table Лифты
…
primary key (№ корпуса, № лифта)
foreign key (№ корпуса) references Корпуса (№ корпуса)
on update cascade
on delete cascade;
Таким образом, мы и задали все необходимые первичные и внешние ключи дочерних классов сущностей. Правило поддержания ссылочной целостности мы снова взяли cascade, так как уже описали его как наиболее рациональный.
Теперь приведем пример в табличной форме всех только что рассмотренных нами классов сущностей. Опишем те базовые отношения, которые отразили при помощи диаграммы, в виде таблиц, и для наглядности введем туда некоторое количество показательных данных.
Корпуса – родительское отношение имеет следующий вид:
Аудитории – дочерний класс сущностей:
Лифты – второй дочерний класс сущностей родительского класса «Корпуса»:
Итак, мы можем видеть, каким образом организована информация по всем корпусам, их аудиториям и лифтам в этой базе данных, которую вполне может использовать любое реально существующее учебное заведение.
Агрегация – это последний вид связи между классами сущностей, который подлежит рассмотрению в рамках нашего курса. Она также не является рекурсивной, и один из двух ее видов довольно близок по смыслу к уже рассмотренной ранее композитной агрегации.
Итак, агрегация – это взаимосвязь одного родительского класса сущностей с несколькими дочерними классами сущностей. При этом взаимосвязи могут быть описаны связями двух видов:
1) обязательно не идентифицирующими связями;
2) необязательно не идентифицирующими связями.
Напомним, что при обязательно не идентифицирующих связях некоторые атрибуты первичного ключа родительского класса сущностей переносятся в неключевой атрибут дочернего класса, и при этом Null-значения для всех атрибутов мигрирующего ключа запрещены. А при не обязательно не идентифицирующих связях миграция первичных ключей происходит по точно такому же принципу, но при этом Null-значения для некоторых атрибутов мигрирующего ключа разрешены.
При агрегации, родительский класс сущностей (или агрегат) связывается с несколькими дочерними классами сущностей (или компонентами). Компоненты агрегата (т. е. родительского класса сущностей) ссылаются на агрегат посредством внешнего ключа, не входящего в состав первичного ключа, и, следовательно, в случае не обязательно не идентифицирующих связей, компоненты агрегата могут существовать вне агрегата.
В случае использования агрегации с обязательно не идентифицирующими связями компонентам агрегата не позволяется существовать вне агрегата, и в этом смысле агрегация с обязательно не идентифицирующими связями близка к композитной агрегации.
Теперь, когда стало понятно, что собой представляет связь типа агрегации, построим ключевую диаграмму, описывающую работу этой связи.
Пусть наша будущая диаграмма описывает маркированные компоненты автомобилей (а именно двигатель и шасси). При этом, будем считать, что списывание автомобиля предполагает и списывание шасси вместе с ним, но не предполагает одновременное списывание двигателя.
Итак, наша ключевая диаграмма имеет следующий вид:
Итак, что же мы видим на этой ключевой диаграмме?
Во-первых, связь родительского класса сущностей «Автомобили» с дочерним классом сущностей «Двигатели» является не обязательно не идентифицирующей, потому что атрибут «№ автомобиля» допускает среди своих значений Null-значения. В свою очередь, Null-значе-ния этот атрибут допускает по той причине, что списывание двигателя, по условию не зависит от списывания всего автомобиля и, следовательно, при списывании автомобиля происходит не обязательно. Также мы видим, что первичный ключ «№ двигателя» класса сущностей «Автомобили» мигрирует в неключевой атрибут «№ двигателя» класса сущностей «Двигатели». И при этом данный атрибут приобретает статус внешнего ключа. А первичным ключом в этом классе сущностей «Двигатели» является атрибут «Маркер двигателя», который не ссылается ни на какой атрибут родительского отношения.
Во-вторых, связь родительского класса сущностей «Двигатели» и дочернего класса сущностей «Шасси» – это обязательно не идентифицирующая связь, потому что атрибут внешнего ключа «№ автомобиля» не допускает среди своих значений Null-значения. Это, в свою очередь, происходит потому, что по условию известно, что списывание автомобиля предполагает обязательное одновременное списывание и шасси. Здесь, так же, как и в случае предыдущей связи, первичный ключ родительского класса сущностей «Двигатели» мигрирует в неключевой атрибут «№ автомобиля» дочернего класса сущностей «Шасси». При этом первичным ключом этого класса сущностей является атрибут «Маркер шасси», который не ссылается ни на какой атрибут родительского отношения «Двигатели».
Идем дальше. Для наилучшего усвоения пройденной темы, запишем снова фрагменты операторов создания базовых отношений «Двигатели» и «Шасси» с определением правил поддержания ссылочной целостности.
Create table Двигатели
…
primary key (Маркер двигателя)
foreign key (№ автомобиля) references Автомобили (№ автомобиля)
on update cascade
on delete set Null
Create table Шасси
…
primary key (Маркер шасси)
foreign key (№ автомобиля) references Автомобили (№ автомобиля)
on update cascade
on delete cascade;
Мы видим, что правило поддержания ссылочной целостности мы использовали везде одно – cascade, так как еще раньше признали его наиболее рациональным из всех. Однако на этот раз мы использовали (помимо правила cascade) еще и правило поддержания ссылочной целостности set Null. Причем использовали мы его при следующем условии: если какое-то значение первичного ключа «№ автомобиля» из родительского класса сущностей «Автомобили» будет удалено, то значению ссылающегося на него внешнего ключа «№ автомобиля» дочернего отношения «Двигатели» будет присвоено Null-значение.
Если при миграции первичных ключей некоего родительского класса сущностей в один и тот же дочерний класс попадают совпадающие по смыслу атрибуты из разных родительских классов, то эти атрибуты необходимо «слить», т. е. необходимо провести так называемую унификацию атрибутов.
Например, в случае, когда сотрудник может работать в организации, числясь не более чем в одном отделе, после унификации атрибута «Код организации» получим следующую ключевую диаграмму:
При миграции первичный ключ из родительских классов сущностей «Организация» и «Отделы» в дочерний класс «Сотрудники», атрибут «Код организации» попадает в класс сущностей «Сотрудники». Причем дважды:
1) первый раз с маркером PFK из класса сущностей «Организация» при установлении не полностью идентифицирующей связи;
2) и второй раз, с маркером FK с условием допустимости Null-значений из класса сущностей «Отделы» при установлении не обязательно не идентифицирующей связи.
При унификации атрибут «Код организации» получает статус атрибута первичного / внешнего ключа, поглощающего статус атрибута внешнего ключа.
Построим новую ключевую диаграмму, демонстрирующую сам процесс унификации:
Таким образом и произошла унификация атрибутов.