Реляционная модель
Создателем реляционной модели считается математик Эдгар Фрэнк Кодд (Edgar Frank Codd, 1923–2003). Датой рождения реляционной теории можно считать июнь 1970 года. Именно тогда Кодд (на тот момент времени сотрудник одной из лабораторий корпорации IBM) опубликовал свою знаменитую статью «Реляционная модель данных для больших совместно используемых банков данных» (Codd E. F. A Relational Model of Data for Large Shared Data Banks. CACM 13: 6), в которой впервые прозвучал столь популярный сегодня термин «реляционная модель».
Первопричиной возникновения нового по тем временам подхода к проектированию баз данных послужили существенные ограничения предыдущих моделей. Ни сетевая, ни иерархическая модели не были способны просто и доступно описывать подлежащие учету данные. Кодд сумел объединить на первый взгляд несовместимые вещи – с одной стороны, реляционная модель опиралась на строгие математические выкладки, а с другой – была понятна рядовому пользователю, состоящему в конфронтации даже с таблицей умножения.
Модель данных не представляет существенного интереса для обычного пользователя, но без нее не обойтись разработчику БД. Ведь это не что иное, как чертеж будущей БД. Как ни один строитель не начнет строить дом без чертежа, так и ни один программист не станет реализовывать физическую БД без ее подробной схемы. Фундамент реляционной модели построен на понятии сущности и связей между сущностями.
Реляционной модели данных посвящено много фундаментальных трудов, в которых подробно изложены все ключевые аспекты модели.
Любая область знаний, будь это математика, радиоэлектроника, физика, химия или информатика, по мере своего развития формирует свой набор терминов и определений. Без этого никак не обойтись, ведь в своих ученых беседах специалисты оперируют понятиями, не имеющими аналогов в окружающем мире. Зачастую размерность специфичных понятий разрастается до такой степени, что существенная часть времени, отводимого на изучение интересующего нас предмета, затрачивается только на формирование словарного запаса. С точки зрения сложности семантики, системы управления базами данных в общем, и реляционная модель в частности не являются исключением из правил. Эта сравнительно новая область знаний практически мгновенно успела обзавестись специфичным набором словарных конструкций. Многие термины перекочевали в БД из лексикона программистов, часть определений позаимствована из теории множеств, в тезаурусе разработчиков моделей данных даже нашлось место для понятий, обычно встречающихся в справочниках по философии.
Сущность и атрибуты
Любой более-менее подготовленный пользователь твердо знает, что базы данных предназначены для хранения и обработки информации. Если в руки такому человеку попадется база городских телефонов, то, даже не запуская программу, он сможет предположить, что в ней он обнаружит телефонные номера граждан и организаций. База данных городской библиотеки обязана содержать информацию об авторах и их бессмертных произведениях. Столкнувшись с базой данных авиакомпании, с высокой степенью вероятности можно утверждать, что в ней мы найдем информацию о расписании полетов, марках самолетов и городах, в которые они доставляют пассажиров.
То, что кажется элементарным для стороннего наблюдателя, для профессионального разработчика БД может стать очень непростым делом. На самом первом этапе проектирования будущей БД он ломает голову над двумя ключевыми вопросами:
1. Что подлежит хранению в БД?
2. Какие связи между данными следует поддерживать в БД?
Для получения ответа на первый вопрос разработчик должен со ставить первоначальный перечень типов сущностей. Тип сущности (entity) – это класс однотипных объектов, о которых следует хранить информацию в БД. Немного забегая вперед, оговоримся, что на заключительной стадии проектирования типы сущности превратятся в реляционные таблицы. В 90 % случаев сущность – это какой-то объект, отвечающий на вопрос «Кто?» или «Что?». В базе данных библиотеки на роль сущностей претендуют такие одушевленные и неодушевленные объекты, как автор, книга, издательство, читатель. Совсем не обязательно, чтобы сущность соответствовала объектам реального мира, напротив, она может моделировать и отвлеченные понятия, допустим выраженные в особых отношениях между сущностями. Именно в таком случае сущность ловко маскируется под глагол. Как правило, это происходит в тех случаях, когда учету подлежат некоторые события. Например, когда читатель получает (это и есть глагол) книгу из библиотечного фонда, логика базы данных требует сохранить информацию о том, кому, когда и какая из книг была выдана. При более подробном рассмотрении выясняется, что при построении первоначального списка мы просто не выявили такой тип сущности, как читательская библиотечная карточка, в которую и делаются все перечисленные выше пометки. Библиотечная карточка поддерживает двустороннюю связь между сущностями «читатель» и «книга».
Если тип сущности – это класс однотипных объектов, то как же величать отдельный объект, входящий в этот класс? В реляционной модели такой объект называют экземпляром сущности. Экземпляр сущности (или просто сущность) – это конкретная реализация объекта. Для сущности «автор» – это Уильям Шекспир и Лев Толстой, для сущности «книга» это «Ромео и Джульетта» и «Война и мир».
Экземпляр сущности – это то, о чем (или о ком) следует хранить информацию в БД. В реальной базе данных экземпляру сущности будет соответствовать одна строка таблицы.
У любой сущности есть свои характеристики. У сущности «самолет» из базы данных авиакомпании таких характеристик сотни. Это марка, максимальная скорость полета, число посадочных мест, грузоподъемность, дата выпуска, цвет фюзеляжа и многое-многое другое. У сущности «читатель» отличительных признаков не меньше, а может быть и больше, чем у летательного аппарата. В счет может пойти все, начиная с цвета глаз и заканчивая размером обуви. Однако в библиотечной базе данных вряд ли стоит учитывать рост, вес и отпечатки пальцев клиента. Гораздо полезнее знать имя, домашний адрес и номер телефона. Отличительные свойства сущности называют атрибутами.
Атрибуты могут быть простыми (например, название города, в который летит самолет) и составными (т. е. включать в себя несколько простых атрибутов). В качестве составного атрибута выступает адрес читателя. Здесь найдется место почтовому индексу, городу, улице, дому и номеру квартиры. Атрибут может быть производным, то есть полученным в результате проведения какой-то операции над другими атрибутами. Подобные атрибуты часто встречаются при построении различных бухгалтерских систем, например значение взимаемого с сотрудников предприятия налога составляет определенный процент от заработной платы этих служащих. Можно столкнуться с многозначными атрибутами, они описывают те свойства сущности, в которых одновременно хранится несколько значений. Например, у одного человека может быть несколько адресов проживания, несколько контактных телефонных номеров и т. п. Есть и особая разновидность атрибутов, без которых невозможно построение реляционной модели, – это атрибуты, однозначно идентифицирующие экземпляр сущности. На роль такого атрибута в состоянии претендовать индивидуальный номер налогоплательщика или уникальный заводской номер самолета. Позднее подобные атрибуты превратятся в ключи реляционных таблиц.
Построив исчерпывающий список типов сущностей и подготовив перечень их атрибутов, разработчик модели базы данных должен задуматься над особенностями реализации типов сущностей. Для этого в первую очередь следует разобраться с особенностями физического представления каждого из атрибутов типа сущности, для этого предназначены тип данных и домен.
Тип данных и домен
Отправной точкой процесса построения любой системы хранения и обработки данных по праву считается выбор типа данных. Вне зависимости от того, какой язык программирования вы изучали, при построении новой программы самым первым шагом становится рассмотрение типов данных, имеющихся в распоряжении системы. Типы данных определяют порядок хранения данных в памяти компьютера. Физическая концепция хранения данных зависит от особенностей конкретной платформы, на базе которой функционирует программное обеспечение. Поэтому в разных операционных системах, в разных системах управления базами данных число байт, отводимых для описания целого или вещественного числа, может отличаться. Например, в 32-разрядных приложениях размерность целого числа INTEGER равняется 4 байтам. В 64-битных системах это утверждение может оказаться ошибочным, ведь здесь проще адресовать 8-байтную переменную.
Типизация хранимых значений не просто указывает на размерность в байтах, которую должна выделить система для размещения в памяти того или иного значения. Преследуемая цель еще более значима. Типизация определяет, какие операции могут быть осуществлены с теми или иными данными. Среда разработки не позволит новичку передать результаты деления в целочисленную переменную, ведь в этом случае есть риск утерять дробную часть результата. Система станет отчаянно сопротивляться, если мы попробуем просуммировать символьный и вещественный типы данных. Пусть даже в символьной переменной хранится числовое значение. В последнем случае перед проведением математической операции необходимо повести преобразование данных. Точно так же СУБД не допустит ввода текстовых данных в поля таблиц, предназначенных для хранения числовой информации.
Подытожим все вышесказанное. Понятие тип данных интегрирует в себе три компоненты:
- ограничение множества принадлежащих типу значений;
- дефиниция применяемых к типу набора операций;
- определение способа отображения (внешнего представления) значений типа.
Как показала практика, при обработке данных в современных информационных системах возможностей обычной типизации становится недостаточно. Примеров тому великое множество. Формально при определении атрибута, хранящего дату рождения сотрудников како-го-нибудь предприятия, следует ограничиться типом данных DATETIME. Но такой подход не способен в полной мере отразить задачи отдела кадров. Стандартизированный в SQL тип данных DATETIME допускает ввод даты в диапазоне от 1/01/0000 до 12/31/9999. Вряд ли начальник отдела кадров примет на работу сотрудника в несовершеннолетнем возрасте или, наоборот, ровесника Ивана Грозного. Поэтому атрибут «дата_рождения» должен уметь сопротивляться некорректным, с точки зрения пользователя, но абсолютно верным с точки зрения типа данных DATETIME данным. Есть и другой пример. Допустим, что в базе данных хранится почтовый индекс. Каждый поклонник эпистолярного жанра знает, что это комбинация из 6 цифр, отражающая региональную принадлежность почтового отделения. Порядок описания индекса не сложен для человека – надо заполнить все шесть значений, не четыре, не пять и не семь, а только шесть. Теперь попробуйте подыскать стандартный тип данных, способный однозначно решить эту простейшую задачу. Тип INTEGER не подходит, потому что обладает существенно большим диапазоном значений. Строка из шести элементов CHAR также не вполне адекватна, ведь она позволяет пользователю вводить любые (не только цифровые) символы. Наконец, еще один пример. Формально номер вашего телефона можно типизировать как целое число – INTEGER. Целые числа поддерживают все основные арифметические операции. Однако никому в здравом уме и в доброй памяти не придет в голову идея суммировать значения телефонных номеров или вычитать из одного номера другой, хотя формально это обычные целочисленные значения. Просто очень сомнительна практическая ценность полученного результата. В подобных и во многих других схожих ситуациях одна лишь типизация бессильна – она в недостаточной степени поддерживает человеческую логику. Если автор смог убедить читателя, что возможностей типа данных недостаточно для описания характеристик атрибутов, закончим с примерами и поговорим о том, как это ограничение можно преодолеть.
Фундаментальная для современных языков программирования идея типизации в реляционной модели получила дальнейшее развитие. На сцену вышло новое понятие – домен (domain). Домен ни в коем случае не подменяет понятие типизации, а выступает в качестве дополнительного ограничителя обрабатываемой в базе данных информации. Ограничение накладывается за счет введения дополнительных логических правил. Так, принимая нового сотрудника на работу, при вводе даты рождения можно контролировать его возраст путем элементарного сравнения текущей системной даты компьютера и даты рождесимволами типа CHAR, наложим дополнительное ограничение на диапазон приемлемых значений – наш домен должен пропускать только цифровые знаки. Надо сразу оговориться, что логические правила являются не столько описанием отдельного домена, сколько средством поддержания целостности данных в масштабах всей базы данных. Допустим, вы вводите почтовый индекс города Москвы, а в атрибут города передаете Монреаль. В этом случае разумная база данных должна намекнуть нам, что мы сегодня перетрудились и следует прерваться на чашечку кофе… Но для того, чтобы система смогла выявить подобную логическую ошибку, разработчик БД должен построить не только строгий набор доменных ограничений, но и реализовать развитую систему поддержания корпоративной целостности.
В профессиональных СУБД доменные ограничения могут накладываться на несколько атрибутов одновременно, таким образом одновременно контролируя непротиворечивость хранящихся в них данных.
Связь
Реляционная модель призвана не только описать перечень типов сущностей, но и отразить особенности взаимодействия между ними. Взаимодействие возникает там, где между типами сущностей проявляются отношения, выраженные в виде глагола, например продавец оформил заказ. Здесь «продавец» и «заказ» – это две сущности, а связь между ними просматривается в глаголе «оформил».
Различают три типа связи между сущностями: «один к одному», «один ко многим» и «многие ко многим». Появление в реляционной БД связи «один к одному» – крайне редкий случай. Чаще всего он свидетельствует о том, что разработчик не вполне корректно определился с атрибутами и вместо одного из атрибутов создал лишний тип сущности. На практике наиболее распространена связь «один ко многим», например автор написал много книг, завод выпустил много автомобилей, в одном отделе работает много сотрудников (рисунок)
Связь «многие ко многим» встречается реже: офисы разных компаний размещены в разных городах, множество издательств опубликовало произведения различных авторов и т. п. Реляционная модель напрямую не поддерживает отношение «многие ко многим», поэтому его приходится разбивать на два отношения «один ко многим».
Есть еще один классификационный признак связи – степень (размерность). При выявлении связей между сущностями разработчик обычно встречается с унарными (unary relationship) и двойными связями (binary relationship), но в реальной жизни имеют место связи и большей кратности. Например, выражение «авиакомпания доставляет пассажира в город» подразумевает тернарную связь (ternary relationship). Здесь мы сталкиваемся с тремя существительными-сущностями: «авиакомпания», «пассажир» и «город» – и всего одним глаголом «доставляет». Дальнейшее развитие модели такой базы данных во многом зависит от опыта и интуиции разработчика, ведь разные пассажиры вправе летать в разные города, пользуясь услугами разных авиакомпаний. Ограничившись лишь услугами двойных связей, можно утратить суть сохраняемой информации – какая из авиакомпаний в какой именно из городов доставила конкретного пассажира. К вопросу построения связей класса «многие ко многим» мы вернемся в следующей главе при обсуждении процесса ER-моделирования, а пока обсудим еще одну особенность связи.
Реляционная модель позволяет связывать сущность саму с собой – задавать рекурсивную связь. Такой, на первый взгляд несколько необычный, способ взаимодействия оказывается весьма полезным при «выращивании» древообразных конструкций, например, описывающих организационную структуру предприятия, завода или, скажем, университета. Здесь четко просматривается иерархия, в которой одна и та же сущность может быть главной по отношению к подчиненным элементам и одновременно находиться в подчиненном состоянии к более высокому по рангу узлу. Так, дочерними элементами по отношению к деканату факультета выступают кафедры этого факультета, в свою очередь, деканат подчиняется ректорату учебного заведения.
Отношение
Дословный перевод термина «relation» – отношение. Что понимается в реляционной теории под отношением?
Вся информация, собранная в реляционной БД, рассматривается пользователем как совокупность взаимосвязанных двумерных таблиц, в каждой из которых хранятся данные о строго определенном типе сущностей. Реляционная таблица состоит из строк и столбцов. Каждая строка содержит информацию о конкретной сущности; так, в таблице «VENDORS» из базы данных склада мы увидим строки с данными о компаниях, производящих электронику и бытовую технику (рисунок).
Но в этой таблице не должно оказаться ни единой строки о клиентах нашей фирмы – покупателях, ведь это другой тип сущности. Каждый столбец реляционной таблицы предназначен для хранения определенного атрибута сущности. Для атрибута «VNAME» (полное название фирмы) разработчик таблицы применит текстовый тип данных размерностью в 50–60 символов. А на атрибут «EMAIL» будут наложены дополнительные доменные ограничения, проверяющие наличие символа «@» и других правил построения почтового адреса.
Терминология реляционных баз данных складывалась из нескольких областей знаний, поэтому в качестве синонимов к понятию «строка» можно услышать слова «запись» и «кортеж». У термина «столбец» также есть два тождественных понятия: «атрибут» и «поле». Ведя речь о таблице, вполне корректно применять термин «отношение».
Некоторые из перечисленных требований нуждаются в комментариях. Уникальность имен столбцов требуется соблюдать только в рамках одного отношения, и ничто не запрещает использовать одинаковые имена в различных таблицах. Так, если название фирмы будет храниться в столбце «VNAME» таблицы «VENDORS», то при необходимости вполне допустимо задействовать такое же имя столбца в других отношениях. Для обращения к требуемому столбцу средствами языка SQL требуется указать название соответствующей таблицы и ее столбца. Например, запрос
SELECT VNAME FROM VENDORS;
возвратит все названия фирм, поставляющих нам товары.
Суть запрета нахождения в реляционной таблице одинаковых строк легко объяснима. Во-первых, дублирование данных противоречит теории множеств, ведь классическое множество должно состоять из различных элементов. Во-вторых, повтор идентичных данных приводит к бессмысленному расходованию дискового пространства и оперативной памяти. В-третьих, дубликаты данных вносят существенную путаницу в работу программы. Представьте, что в студенческой группе учатся два тезки, скажем Иван Иванов и Иван Иванов. Один из них – круглый отличник, а другой – патологический двоечник и прогульщик. Как следствие первого надо перевести на следующий курс, а второго – отчислить. Если записи об этих студентах не будут отличаться хотя бы на микрон (точнее, на бит), то деканат окажется в патовой ситуации, руководству факультета будет не понятно, какую из строк таблицы следует удалить, а какую оставить. Обеспечение требования уникальности строки достигается путем ввода в таблицу дополнительных атрибутов, в частности отчества, даты рождения, номера и серии паспорта и т. п. На основе одного или нескольких уникальных столбцов формируются особые столбцы, называемые ключевыми.
На пересечении строки и столбца должно находиться единственное значение. Это значение должно быть атомарным, т. е. неделимым. Примером нарушения атомарности может стать попытка записи в одну ячейку таблицы группы значений, например, нескольких названий фирм. Подобный подход также затрудняет процесс поиска и обработки информации.
Последнее из перечисленных требований об обработке строк и столбцов в любом порядке в меньшей степени заботит разработчика БД, так как оно реализуется автономно средствами современных СУБД. Заметим, что отсутствие требования упорядоченности не усложняет, а наоборот – значительно упрощает процесс разработки БД. Поэтому, заполняя список студентов, поступивших в вуз, не следует заботиться о соблюдении алфавитной последовательности при внесении новых строк. При необходимости получить упорядоченную по фамилии (или любому другому атрибуту/атрибутам) ведомость можно буквально в два счета, добавив в инструкцию SQL ключевое слово ORDER BY и перечень атрибутов сортировки. Порядок вывода столбцов точно так же назначается программистом средствами SQL.
Ключи
В составе любого реляционного отношения всегда должен присутствовать столбец (или группа столбцов), содержимое которого предназначается для хранения значений, способных уникальным образом идентифицировать строку таблицы. Допустим, мы проектируем таблицу для отдела кадров, предназначенную для хранения сведений о сотрудниках предприятия. Таблица станет содержать интуитивно понятный набор столбцов (ФИО, дата рождения, специальность, образование и т. п.), описывающих человека. Какие столбцы следует сделать ключевыми?
На роль ключевых вряд ли смогут претендовать столбцы, хранящие фамилию и имя человека. Если на вашем предприятии на данный момент времени не работают два полных тезки, это совсем не означает, что это исключено в будущем. Поэтому разработчику стоит сразу включать в таблицу поля с безусловно уникальной информацией для описываемой сущности, например, индивидуальный номер налогоплательщика для человека или номер двигателя и кузова для автомобиля. Но и с такими данными могут произойти неприятности. Допустим, что мы выбираем в качестве ключа атрибут, содержащий информацию о серии и номере паспорта гражданина. Вряд ли кто со мной не согласится, что это уникальные данные и, на первый взгляд, вполне подходящие в качестве кандидатуры на ключ. Но паспорт может быть заменен (в результате потери, стихийного бедствия, плановой смены паспортов и т. п.). В результате у человека появляется новый паспорт с другими серией и номером, это влечет за собой сложную процедуру изменения значений первичного ключа и связанных с ним внешних ключей во всей базе данных. Если приходится исправлять две-три строки в таблице, то ничего страшного. А если паспорта заменили у всех граждан страны?
Поэтому чаще разработчики добавляют к таблице атрибуты, предназначенные для хранения искусственной информации, обычно это целочисленные поля автоинкрементного типа. Идея работы подобного столбца в том, чтобы при внесении в таблицу очередной строки значение атрибута получало приращение (обычно плюс единица, хотя во многих СУБД это значение настраиваемое). Простая и, как следствие, надежная логика работы счетчика исключает любую вероятность повтора значений в автоинкрементных полях – каждая новая строка в ключевое поле запишет новое значение. Если вы ненадолго вернетесь к рисунку, на котором представлено отношение между сущностями «Отдел» и «Сотрудник», то увидите, что для сущности «Отдел» в качестве первичного ключа введен атрибут «ключ_отдела», а для сущности «Сотрудник» – «ключ_сотрудника».
Первичным ключом (PK, Primary Key) называют ключ, отвечающий за уникальную идентификацию строки в реляционной таблице.
Помимо первичных ключей, в таблицах активно применяется еще одна разновидность ключевого поля – внешний ключ (FK, Foreigner Key). Благодаря внешнему ключу мы получаем возможность строить реляционные связи между таблицами. На рисунке внешний ключ имеется у сущности «Сотрудник», это атрибут «ключ_отдела». Если мы хотим указать, что сотрудник Арбузов не покладая рук трудится в бухгалтерии предприятия, то мы делаем следующее:
- узнаем значение первичного ключа у строки «Бухгалтерия» (в нашем примере это 2);
- передаем это значение во внешний ключ строки с сущностью «Арбузов».
Таким образом, поле внешнего ключа сущности «Сотрудник» может содержать любое из значений первичного ключа сущности «Отдел».
Целостность данных
Мы уже знаем, что база данных – это не просто сосуд, который постепенно заполняется произвольной информацией. БД еще призвана на установленном разработчиком уровне абстракции отражать взаимоувязанные объекты реального мира. Чем точнее данное отражение, тем совершеннее база данных. Зеркало также призвано отражать объекты реального мира, но каждый из нас знает, что оно склонно к искажению действительности. Объект, попавший в зазеркалье, уже не тот, что находится снаружи. Поэтому, кроме функций зеркала, БД должна содержать некоторый набор правил, которые позаботятся о том, чтобы данные всегда находились в согласованном состоянии.
Целостность данных (data integrity) – соответствие значений всех данных базы данных определенному непротиворечивому набору правил
Можно выделить три базовых класса правил, призванных поддерживать целостность данных в реляционной БД:
1) целостность доменов;
2) целостность сущностей;
3) ссылочная целостность.
Кроме того, существует понятие корпоративной целостности, это не что иное, как реализация в БД бизнес-правил, присущих конкретному предприятию.
Целостность доменов
Целостность доменов поддерживается за счет механизма доменных ограничений. Это как раз тот случай, когда описание домена включает некие логические правила, отбраковывающие некорректные значения, которые так настойчиво стремятся попасть в атрибуты нашей таблицы. В простейшем случае допустимые значения могут быть просто перечислены, например «понедельник», «вторник» и т. д. Может быть объявлен диапазон допустимых значений, например от 2 до 5, если речь идет об оценках учеников. Все зависит от возможностей СУБД, в которой мы создаем наши проекты.
Особая роль в поддержании доменной целостности отводится особому определителю NULL. NULL обозначает неопределенность или неизвестность. При проектировании БД разработчики выявляют обязательные атрибуты, без которых работа БД невозможна, и атрибуты, к которым применяются пониженные требования, например которые разрешено заполнить позднее или не трогать вовсе. Допустим, что вы вводите в БД анкетные данные сотрудников и у кого-то из них пропущена дата рождения. Что делать? Поставить дату на глазок? Это может привести к искажению фактов (БД призвана отражать, а не искажать объекты реального мира), и впоследствии отдел кадров отправит своего сотрудника раньше на пенсию. Если система способна понять, что ячейка таблицы хранит не значение, а неопределенность, то можно избежать подобной неприятности. Есть и другой пример. В вуз зачислено несколько сотен абитуриентов, но зачетные книжки и студенческие билеты на них пока не заполнены. Номера билетов и «зачеток» – это обязательные, безусловно подлежащие учету данные. Что же? Прекратить ввод уже известной информации (имена, адреса, номера телефонов и т. п.), пока первокурсникам не раздадут все документы? А может статься так, что документы невозможно оформить, пока в БД не появитсяинформация о новых студентах. Получается замкнутый круг. Посему грамотно спроектированная база данных просто обязана позволить нам ввести имеющиеся на сегодня данные, отложив на завтра заполнение неопределенных атрибутов.
Определитель NULL может оказаться полезен при организации связи между таблицами, если поле внешнего ключа допускает неопределенное значение, то это служит признаком, что связь необязательна.
Целостность сущностей
Как недвусмысленно следует из названия, целостность сущностей направлена на обеспечение внутреннего единства отдельной сущности. Вне зависимости от того, что мы намерены хранить в наших таблицах, следует соблюдать краеугольное правило – каждая строка таблицы обязана быть уникальной. А для этого нужно контролировать корректность первичного ключа отношения (если вы подзабыли, то напомню: первичный ключ – это минимальный уникальный идентификатор кортежа в отношении). Суть требования к первичному ключу проста – во входящих в его состав атрибутах не должно содержаться ни одного определителя NULL. Такое пожелание логично. Ведь если мы допускаем, что во входящем в состав первичного ключа столбце может находиться неопределенное значение, то это означает, что поле перестает поддерживать механизм однозначной идентификации строки таблицы.
Помимо поддержания корректности первичного ключа, целостность сущностей в состоянии обеспечить широкий спектр дополнительных сервисных возможностей. Их перечень определяется профессионализмом разработчика базы данных. Например, было бы хорошо научить БД контролировать непротиворечивость значения, вводимого в атрибут, на основе значений, имеющихся в других атрибутах таблицы или даже в атрибутах других таблиц. База данных железнодорожной кассы обязана уведомить оператора, что пассажир покупает на свое имя два билета в абсолютно противоположных направлениях на одно и то же время. База данных отдела кадров металлургического завода не должна пропустить на вредную работу к мартеновской печи несовершеннолетнего. База данных в деканате не переведет на следующий курс студента, не сдавшего летнюю экзаменационную сессию.
Ссылочная целостность
Реляционная база данных – это не только таблицы с информацией, но и логические связи между ними, а нарушение связи между таблицами может разрушить всю БД. Именно поэтому на стражу реляционных связей поставлено третье правило целостности данных, получившее название ссылочной целостности. Смысл правила в следующем: внешний ключ не может осиротеть, ему всегда должен соответствовать первичный ключ в главной таблице.
Поводов для нарушения связи предостаточно. Во-первых, удаление строки в главной таблице. Допустим (рисунок), мы удаляем строку «Отдел кадров» в таблице «Отделы предприятия». В результате в подчиненной таблице «Сотрудники» оказываются брошенными сотрудники Костенко и Елецкова, ведь их внешний ключ по-прежнему будет хранить значение уже несуществующего первичного ключа. Во-вторых, при добавлении новой записи в таблицу «Сотрудники» во внешнее поле «ключ_отдела» может попасть значение, которому нет соответствия в главной таблице.
В-третьих, ссылочная целостность может подвергнуться опасности при редактировании ключевых полей в главной или подчиненной таблице. В современных СУБД все перечисленные проблемы предотвращаются автоматически, но это не означает, что рядовому разработчику баз данных не стоит задумываться над поддержанием ссылочной целостности в своих проектах.
Реляционная алгебра
Реляционная алгебра базируется на традиционных теоретико-множественных операциях (пересечение, объединение, вычитание и декартово умножение) и дополнена четырьмя операциями (ограничение, проекция, деление и соединение), специфичными для обработки реляционных данных. Все эти операции обрабатывают отношения, которые (по определению) являются множествами кортежей.
Кроме этих операций, в реляционную алгебру включают операцию переименования атрибутов (AS), позволяющую корректно формировать схему (заголовок) результирующего отношения, и операцию присваивания(:=), позволяющую сохранять в базе данных результаты вычисления алгебраических выражений.
- Объединение R := Rl U R2 - результирующее отношение R включает все кортежи, входящие хотя бы в одно из отношений-операндов Rl или R2.
- Пересечение R := R 1 n R2 - результирующее отношение R включает все кортежи, входящие в оба отношения-операнда Rl и R2.
- Вычитание R := Rl - R2 - результирующее отношение R включает все кортежи, входящие в отношение-операнд Rl, такие, что ни один из них не входит в отношение-операнд R2.
- Расширенное декартово произведение R := Rl х R2 - кортежи результирующего отношения R производятся путем попарного соединения (конкатенации, или сцепления) всех кортежей отношений-операндов Rl и R2. Арность результирующего отношения будет равной сумме арностей всех перемножаемых отношений-операндов, а мощность - произведению их мощностей.
Операндами первых трех операций могут быть только совместимые отношения, то есть такие отношения, схемы которых (арность кортежей, имена и типы соответствующих атрибутов) одинаковы. Это ограничение объясняется тем, что результатом операций является отношение, а· в отношении все кортежи должны иметь одинаковые схемы. Отношения-операнды, схемы которых отличаются только именами атрибутов, становятся полностью совместимыми после применения к ним операций переименования.
Операция расширенного декартова произведения отношений применима к отношениям, схемы которых не имеют совпадающих атрибутов, и трактуется иначе, чем базовая теоретико-множественная операция декартова произведения, результатом которой является множество пар элементов перемножаемых отношений. Реляционная модель не использует понятия "пара кортежей", и по этой причине реляционную операцию называют расширенным декартовым произведением. Эта операция не имеет какого-либо содержательного смысла и введена в состав манипуляционной составляющей модели по той причине, что через нее определяются действительно полезные специальные операции соединения отношений.
- Ограничение R := Rl WНERE условие - результирующее отношение R включает подмножество кортежей отношения-операнда Rl, удовлетворяющих заданному условию (любому корректному логическому выражению).
- Проекция R := Rl PROJECT список атрибутов - схема результирующего отношения R включает только те атрибуты исходного отношения R, которые включены в список атрибутов; если ни один из атрибутов этого 'списка не обладает свойством уникальности, в результирующем отношении потенциально возможны кортежи-дубликаты, которые (при их наличии) удаляются из результирующего отношения.
- Деление R := Rl DIVIDE ВУ R2 -бинарное отношение-операнд Rl делится на унарное отношение-операнд R2; результирующее унарное отношение R включает значения первого атрибута кортежей отношения Rl, такие, что множество значений второго атрибута кортежей этого отношения (при фиксированном значении первого атрибута) включает множество значений единственного атрибута кортежей отношения R2.
- Соединение R:=Rl JOIN R2 ON условие - кортежи результирующего отношения R образуются путем соединения (конкатенации, или сцепления) кортежей отношений-операндов Rl и R2, удовлетворяющих заданному условию (любому корректному логическому выражению). Выполнение операции соединения отношений можно рассматривать как операцию их расширенного декартова произведения с последующей фильтрацией множества кортежей полученного промежуточного отношения по заданному условию.
В манипуляционной составляющей реляционной модели определено несколько разновидностей операции соединения:
- Внутреннее соединение (inner join) - соединяются только те кортежи отношений-операндов, для которых выполняется заданное условие;
- Левое (left join) и правое (right join) соединение - результирующее отношение будет безусловно содержать все кортежи левого (или соответственно правого) отношения-операнда, в том числе и те, для которых нет "пары" в другом отношении-операнде, при этом "недостающие" атрибуты в таких кортежах результирующего отношения получат неопределенные NULL-значения;
- Внешнее соединение (foreign или outer join) -одновременно и левое, и правое соединение;
- Эквисоединение ( equal join) - такое соединение, условие которого содержит оператор сравнения "равно";
Естественное соединение (natural join) -эквисоединение двух отношений, имеющих одинаковые атрибуты (как правило, это первичный и внешний ключи соединяемых отношений), равенство которых и является условием соединения кортежей (при этом совпадающий атрибут в схеме результирующего отношения не дублируется).