РАБОТАЕМ С ДАННЫМИ | КОМПЬЮТЕРНАЯ ГАЗЕТА
Зачем нужны связи Была в истории нашей страны такая неоспоримая мудрость: кадры решают все. Со всей ответственностью хочу заметить, что в это бесспорно мудрое изречение закралась одна небольшая ошибка: все решают не сами кадры, а имеющиеся у них связи. Практически без сколько-нибудь серьезных изменений принцип первоочередности связей был перенесен и в идеологию СУБД. (c) Компьютерная газета | Ранее я уже говорил, что любая база данных состоит из таблиц, которые связаны между собой определенными зависимостями. Благодаря таким связям удалось значительно уменьшить объем любой базы данных, особенно в тех случаях, когда информация повторяется. В обычной жизни это можно сравнить с системой личных дел, заводимых на каждого сотрудника предприятия, или амбулаторных карт в поликлинике. Теоретически каждая служба, каждый отдел на предприятии, равно как и каждый врач в поликлинике, нуждаются в полной информации на конкретного человека. Начальник какого-нибудь особо секретного отдела весьма справедливо желает знать, что за люди у него работают и "чем они дышат", ибо, случись что, в первую очередь отвечать придется ему. Точно так же и врач для вынесения окончательного диагноза должен знать, чем и как болел пациент в прошлом, нет ли у него аллергии и так далее. Следовательно, в каждом из вышеописанных случаев на человека должна заводиться толстая папка, в которой будут фиксироваться соответствующие факты, а так как возможных мест контроля чрезвычайно много, то и подобных папок вскоре окажется не меньше. При этом неизбежно возникнет проблема корректности данных, многократно заносимых различными людьми и никак не связанных между собой. Та же амбулаторная учетная медицинская карточка как раз и придумана для решения такой проблемы. Куда бы человек ни переезжал, в какое бы лечебное учреждение ни обращался, он всегда должен иметь при себе эту самую карточку, в которую заносятся все записи и которая, таким образом, превращается во всеобъемлющий источник медицинских данных об этом человеке. Чтобы более наглядно проиллюстрировать назначение механизма связей при организации СУБД любого рода, я приготовил небольшой пример. В последующем совместными усилиями мы сделаем из него небольшую базу данных, предназначенную для небольшого магазина, торгующего книгами. Не поручусь, что он будет полностью соответствовать абсолютно всем современным требованиям (хотя бы с точки зрения реализации всех налоговых постановлений), но на его основе уже не составит большого труда написать действительно "рабочую" базу данных и на самом деле взять ее "на вооружение". А начнем мы этот процесс с одной простой процедуры связывания нескольких таблиц. Если речь зашла о книжном магазине, будем считать, что он не специализированный, а общего профиля, то есть в нем предлагается практически любая литература, какая только вообще пользуется спросом. Есть там немного любовных романов в мягком переплете для домохозяек, есть детективы, есть немного научной фантастики, непременно присутствует справочная литература и уж вовсе обязательно продаются всякие научно-технические книги, прежде всего руководства по вычислительной технике, прикладным пакетам и системному программированию. Теоретически вы можете определить для себя собственный набор рубрик, но в примере использованы пять: научно-техническая, научная фантастика, беллетристика, история и справочники. С этого момента любая книга, поступившая в мой виртуальный магазин, обязательно будет отнесена к одной из рубрик, что определит отдел, в котором она будет выставлена на обозрение покупателей. Отсюда вытекают два важных вывода: какой бы уникальной ни была любая отдельно взятая книга, она все равно окажется в одном из пяти отделов; в системе электронного учета целесообразнее всего реализовать ту же схему, которая применяется в реальной жизни в этом магазине. Каждая книга описывается некоторым набором полей: наименование, автор, наименование издательства, месторасположение издательства, тираж, стоимость. При поступлении на склад к перечисленным добавляется еще один параметр - рубрика. В отличие от прочих, наименование рубрик, равно как и их количество, не является случайным, а определяется администрацией магазина. Значит наиболее рационально организовать учет на основе двух таблиц. В одной будут храниться все данные на конкретное наименование книги, а во второй - перечень применяемых в магазине рубрик. Так обеспечивается необходимая целостность и уникальность информации. Сотруднику склада не придется каждый раз ломать голову над названием рубрики, достаточно будет просто выбрать наиболее подходящую из заранее заданного (возможно даже и не им самим) списка. Это не только сократит затраты времени на документирование поступившей литературы, но еще гарантирует от такой неприятной мелочи, как банальная опечатка. В отличие от человека, компьютеру такое понятие неведомо, а значит слово с опечаткой будет воспринято им как вполне корректное название нового отдела в магазине, ведь его совершенно не волнует: есть такой отдел на самом деле или нет. А чтобы компьютер однозначно ассоциировал рубрикатор с перечнем поступившей литературы, нужно создать связь между логически связанными полями. Для начала следует запомнить, что такая связь основана на кодах. Чтобы в них не запутаться, в Microsoft Access было придумано следующее правило: в главную таблицу из подчиненной передается не само значение связанного поля, а его код. На практике это выглядит следующим образом. В примере подчиненной является таблица рубрикатора, в которой каждому наименованию рубрики соответствует индивидуальное значение поля типа счетчик, названного мною " Код рубрики". Ранее уже упоминалось, что значение поля типа счетчик автоматически увеличивается на единицу каждый раз, как только в таблице появляется новая строка. Таким образом, рубрике " Научная фантастика" соответствует код "2", а, например, рубрике " История" - код "4" (см. рис. 1). Однако на самом деле видимые коды являются исключительно видимыми, внутри самой таблицы реально хранится число в формате длинное целое. Это означает, что в таблице с перечнем литературы должно быть поле с наименованием " Рубрика" (одинаковость наименования связанных полей обязательна, ибо это играет важную роль) и это поле должно иметь тип длинное целое, иначе произойдет ошибка "типа данных" и связь не заработает (см. рис. 2). Теперь приступим к созданию самой связи. Для этого необходимо перейти в режим " схема данных", в котором определяются все связи между любыми элементами СУБД. В Microsoft Access 97 это делается двумя способами: можно воспользоваться режимом СХЕМА ДАННЫХ, расположенном в системном меню СЕРВИС, а можно просто нажать мышью на экранную кнопку "Схема данных", расположенную справа на инструментальной панели рабочего окна СУБД. В любом случае будет инициализирован мастер создания схемы данных, которому понадобится указать, что конкретно вы намерены связать (см. рис. 3). Указание производится предельно просто. Если вы намерены связать только таблицы, то активизируйте вкладку "ТАБЛИЦЫ", если запросы, то вкладку "ЗАПРОСЫ", если и то и другое вместе, то последнюю вкладку "ТАБЛИЦЫ И ЗАПРОСЫ". Теоретически можно было бы сразу кликать по последней вкладке, но в больших проектах обычно есть множество и таблиц, и запросов, а в результате можно окончательно запутаться. Поэтому разработчики Microsoft Access 97 предусмотрели такое вот разделение. В данном случае я буду оперировать только таблицами, а значит активной останется вкладка "ТАБЛИЦЫ", на которой перечислены наименования всех таблиц, имеющихся в данной базе на данный момент. Теперь остается только поочередно выделять мышью нужные таблицы и нажимать экранную кнопку " ДОБАВИТЬ". Это приведет к появлению в окне "Схема данных" прямоугольников с перечисленными в них именами полей. Только не забывайте, что Microsoft Access 97 допускает многократное использование одной и той же таблицы либо запроса в разных системах связей, которые тем не менее отображаются в общем рабочем окне схемы данных, а значит если вы по невнимательности два и более раз "добавите" одну и ту же таблицу (запрос), то и соответствующих им прямоугольников появится такое же количество. Страшного в этом ничего нет, "лишние" прямоугольники в любой момент можно удалить, это никак не сказывается на самих источниках данных, просто будьте внимательны. Когда необходимые таблицы и/или запросы "добавлены", этот диалог можно "закрыть" соответствующей кнопкой. Окно диалога исчезнет, а окно "Схема данных" с добавленными модулями останется (см. рис. 4). Это окно стоит рассмотреть повнимательней. Как я уже говорил, каждый прямоугольник носит название породивших его таблицы или запроса, внутри себя содержит наименования соответствующих полей. Если наименования длинные или их много, то прямоугольники "обзаведутся" лифтами вертикальной и горизонтальной прокрутки. Мне такое не кажется удобным, поэтому я предпочитаю просто растягивать границы окон таким образом, чтобы сразу были видны целиком все поля - полагаю, что так удобнее. Кстати, порядок, в котором прямоугольники размещаются в окне "СХЕМА ДАННЫХ", также не является догмой. Изначально он определяется очередностью "добавления" объектов, но его можно в любой момент изменить простым "перетаскиванием" соответствующего прямоугольника в любое удобное место, точно так же, как подобное делается с любым окном в среде Microsoft Windows 95/98. Прелесть перетаскивания вы, несомненно, ощутите, когда столкнетесь хотя бы с десятком объектов, восприятие которых потребует расположить их в некоторой логической последовательности. Теперь настала очередь непосредственного создания связи. Технически это очень простое действие: нужно "взять" мышью название нужного вам поля и "перетащить" его на соответствующее название поля в другой таблице, после чего "бросить" его там. Связь будет создана автоматически. На практике существует ряд особенностей, подлежащих учету. Чтобы потом не отвечать на излишние глупые вопросы, желательно сразу правильно указать СУБД направление передачи данных. В представленном примере Microsoft Access 97 должен "взять" из рубрикатора код названия рубрики и "передать" его в поле " Рубрика" таблицы "Литература". Значит, "берем" поле " Код рубрики" из таблицы "Рубрикатор" и "перетаскиваем" его на поле " Рубрика" таблицы "Рубрика". Сразу же, как только вы "бросите" значок с названием поля, на экране появится дополнительное окно, на котором от вас потребуется уточнить характер создаваемой связи (см. рис. 5). В первом столбце представленной на нем таблицы должно быть указано название поля, служащего источником информации, в данном случае это " Код рубрики" таблицы "Рубрикатор". Во втором столбце, соответственно, приводится получатель данных. Когда я упоминал о "глупых вопросах", я имел в виду ситуацию, когда ошибка в выборе поля приводит к необходимости "открыть" выпадающий список с названием полей, которым на самом деле является каждая ячейка этой таблицы, и "выбрать" в нем правильное значение. Причем если ошибка с именем поля еще может быть исправлена относительно легко, то поменять местами источник данных с получателем невозможно вообще. Вам придется все "отменить" и заново произвести процедуру перетаскивания полей. Теперь, перед тем как перейти к дальнейшим подробностям настройки связи, непременно следует повнимательнее рассмотреть виды возможных связей. Их на самом деле два, хотя для объяснения всюду применяются три: один-к-одному, один-ко-многим и многие-ко-многим. Связь один-к-одному означает, что, например, на одном корабле может быть только один капитан и никаких других вариаций не допускается. Связь один-ко-многим, наоборот, означает, что, например, один и тот же человек может стать пассажиром такси, самолета или поезда, он может купить билеты разного класса и по разной цене, но это все равно останется один и тот же человек. Третий тип, многие-ко-многим, на самом деле является хаосом, неупорядоченной смесью связей первого и второго типов. Чтобы СУБД могла всегда однозначно определить принадлежность той или иной информации, вы должны ей четко сказать, например, что, говоря " издательство КРАСНАЯ ЗВЕЗДА", вы всегда имеете в виду всего одно издательство, которое называется "КРАСНАЯ ЗВЕЗДА" и которое расположено в городе Москве по строго определенному адресу, а также всегда имеете в виду, что в мире не существует никакого другого одноименного издательства, расположенного в том же городе и так далее. Если представить это двумя таблицами, в одной наименования и адреса издательств, а в другой - названия книг, то между ними, при соблюдении указанного условия, должна быть образована связь один-к-одному. А вот в создаваемой нашими совместными усилиями базе данных для частного магазина "Рубрикатор" связан с таблицей "Литература" связью один-ко-многим, так как в одной рубрике всегда будут книги с совершенно разными названиями. По умолчанию СУБД Microsoft Access 97 автоматически подразумевает, что вы создаете связь один-ко-многим, что отражается в окне " Тип отношения", но это можно изменить. Второй важной характеристикой связи является ее задача в плане обеспечения целостности данных. В использованном примере, теоретически, ничто не мешает, допустим, директору вдруг прийти утром на работу и заявить, что с этого дня вводится новая рубрика, к примеру, "эротика". Не беда, что в новом отделе пока нечего выставить, соответствующему "ответственному за снабжение" человеку "будет поставлена задача" и через некоторое время он "достанет" нужные книги. Следовательно, ситуация, при которой рубрика есть, а ее содержимого по тем или иным причинам нет, допускается. Но ведь может быть и по-другому. Сложно, например, представить себе ситуацию, когда банк будет продолжать начислять проценты по остатку счета, который уже закрыт его владельцем и, следовательно, больше не существует. Чтобы не нанимать отдельного сотрудника для отслеживая всех подобных ситуаций, в рамках одной базы данных в Microsoft Access 97 реализовано свойство Обеспечение целостности данных, которое должно взять на себя решение подобной задачи. При его активизации система не допустит возникновения коллизии, то есть логического противоречия, когда, например, новая книга на склад поступила и была там оприходована, но не оказалась отнесена ни к одной из рубрик. Правда, с определением этого свойства стоит быть осторожным, так как при жесткой привязке база данных не допустит и обратной ситуации, той, когда "директор как-то утром внезапно приказал..." и вам придется писать отдельный программный модуль, который будет одновременно создавать новую рубрику и одновременно хотя бы одну запись о книге, ей соответствующей. Правда, при корректном подходе можно вообще переложить на связь даже такое относительно сложное действие, как "каскадное удаление связанных полей" или "каскадное обновление связанных полей". Допустим, случилось неприятное и один из ваших постоянных клиентов навсегда уехал не только из данного города, но и вообще из страны, а значит он больше не будет покупать у вас книги. Следовательно незачем хранить в базе записи о нем. Но записей много, они разбросаны по разным таблицам и переплетены множеством разнообразных связей. В ручном режиме их удаление можно смело использовать в воспитательных целях, так как сия процедура является сущим кошмаром. Однако если "сказать" мастеру, что "обеспечение целостности связей - да" (то есть поставить галочку в соответствующем окошке), а потом еще раз сказать "да" в окне "каскадное удаление связанных полей", то система сама будет следить за всеми связанными данной связью записями и удалит всю подчиненную информацию в том случае, если, например, вы удалите из рубрикатора название какой-либо рубрики. Теперь, когда вы нажмете кнопку " ОК", окно дополнительной настройки пропадет, а между прямоугольниками, обозначающими соответствующие таблицы, появится тонкая черная линия, соединяющая указанные выше поля. Эта линия и обозначает связь между полями. Если теперь попытаться переместить любую из таблиц по экрану, то эта связь все равно сохранится. Остается рассмотреть всего лишь одну тонкость, которой является степень связанности данных. Если выделить маркером вязующую линию, нажать правую клавишу мыши и выбрать в появившемся контекстном меню режим ИЗМЕНИТЬ СВЯЗЬ, то на экране опять появится настроечный мастер (см. рис. 5). Теперь следует нажать расположенную на нем экранную кнопку " ОБЪЕДИНЕНИЕ", раскрыв тем самым еще один дополнительный мастер (см. рис. 6). По умолчанию Microsoft Access 97 объединяет по связи только те поля обеих таблиц, значения которых совпадают. Однако, как это однозначно видно из сопроводительных надписей, допускаются и другие варианты объединения. В зависимости от конкретной ситуации, вы можете активизировать любой из них. Далее, как всегда, "ОК" и все. Теперь связь полностью сформирована. Александр Запольскис E-mail:leshy@nestor.minsk.by