Основы моделирования и базы данных

Физическая реализация. Часть 4

В лекции детально разбирается практическое проектирование реляционной базы данных для кинотеатра. Изложение строится на последовательном создании таблиц, начиная с сущности «Расписание» и её сложных связей. Далее моделируются сотрудники с применением категориального разделения (отношение «один к одному»). Логика завершается моделированием процесса продажи: созданием таблиц заказов и их детализации, анализом первичных ключей и обеспечением ссылочной целостности. В конце демонстрируется критически важная для любого проекта процедура резервного копирования и восстановления базы данных.

Основные мысли

В результате изучения лекции слушатель будет способен:
1. Спроектировать таблицу для хранения расписания сеансов с составным первичным ключом.
2. Объяснить разницу между отношениями «один ко многим» и «один к одному» на уровне физической модели.
3. Применить метод категориального разделения для моделирования подтипов сущностей.
4. Оценить сложность первичного ключа и принять решение о введении суррогатного ключа.
5. Разработать структуру для хранения заказов и их детализации.
6. Выполнить полное резервное копирование (backup) и восстановление (restore) базы данных.
Показывать лекцию целиком
Краткое изложение

Бэкап базы данных - Cinema.backup.

Для тех слушателей, кто имеет старую версию SQL Server и не может развернуть Cinema_final, предлагается следующая последовательность действий:

  1. Сделать бекап своей базы данных Cinema
  2. Удалить свою базу данных Cinema
  3. Открыть приложенный скрипт cinema.sql
  4. В самом начале скрипта (строки 5 и 7) есть путь до папки SQL Server, который на вашем компьютере может немного отличаться (см. приложенный скрин). Замените путь на ваш правильный (скорее всего, надо будет только цифры 15 в названии папки исправить).
  5. Исполните скрипт.
  6. Обновите список баз данных, найдите Cinema и назначьте владельца в свойствах базы

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

Если при установке бэкапа базы данных "Cinema" с помощью SQL Server Management Studio она появилась в списке, компоненты отобразились в списке, но при попытке открыть dbo.Diagram открывается пустое окно, то для того, чтобы отображались данные в этом разделе нужно:

  1.  Правой кнопкой мыши нажать на базе данных, выбрать: Свойства-раздел Файл-назначить владельца БД после восстановления.
  2. В диаграмме нажать правой кнопкой мыши, выбрать: Добавить таблицы-добавить все таблицы БД. Диаграмма автоматически построится.

Приложения

Cinema.backup
Создание таблицы «Расписание»

Начнём с таблицы для расписания. Для хранения информации о сеансе необходимо знать: какой фильм, в каком формате, в каком зале и в какое время демонстрируется.

Создадим таблицу «Расписание».

StartDate: поле типа DateTime. Отвечает за дату и время начала сеанса.
ID Hall: поле типа int, ссылка на зал.
ID Film: поле типа int.
ID Format: поле типа int.

Поля ID Film и ID Format вместе ссылаются на пересечение сущностей «Фильм» и «Формат». Комбинация полей StartDate, ID Hall, ID Film и ID Format образует первичный ключ.
Протягиваем связи к таблицам «Холл» и «Фильм-Формат». Получаем рабочую схему для хранения сеансов.

Сотрудники и должности

Следующий шаг — работа с персоналом.
Создаём таблицу-справочник «JobList» (список должностей).

ID: первичный ключ.
Job Title: название должности (varchar).
Comment: необязательное поле для должностных обязанностей (varchar(max)).

Далее создаём таблицу «Person» (сотрудник):
Personal Number: табельный номер сотрудника, выполняет роль первичного ключа (int).
FirstName, SecondName: имя и фамилия (varchar(30)).
BirthDate: дата рождения (date).
Passport Number: номер паспорта (int).
Job Title ID: внешний ключ к таблице JobList.

Категориальное разделение (отношение «один к одному»)

Из всех сотрудников нас интересуют только кассиры, так как процесс продажи билетов обслуживают именно они. Для выделения специфических атрибутов кассира используем категориальное разделение.
Это реализуется через связь «один к одному».
Создаём таблицу «Cashier» (кассир):
Personal Number: первичный ключ, который полностью совпадает с ключом родительской таблицы Person.
Cash Register Number: номер кассы — атрибут, свойственный исключительно кассиру.

При полном совпадении первичных ключей связь «один к одному» определяется автоматически. В эту таблицу будут попадать только те сотрудники, которые являются кассирами.

Заказ (Order) и проблема суррогатного ключа

Моделируем факт покупки. Нам нужно знать, на какой сеанс куплен билет, когда совершена покупка и какой кассир обслужил заказ.
Создаём таблицу «Order» (заказ). Первоначально в неё попадают поля из «Расписания»:
StartDate
ID Hall
ID Film
ID Format
и добавляются специфические поля:
Order Date: дата и время совершения заказа.
ID Person: идентификатор кассира.

В итоге получаем комбинацию из шести полей для первичного ключа. Это очень сложный ключ. Чтобы упростить работу и дальнейшие ссылки, вводим суррогатный ключ — дополнительное поле ID, которое и станет первичным ключом. После этого настраиваем связи от таблицы Order к таблицам «Расписание» и «Cashier».

Детализация заказа (Order Detail)

Заказ завершает таблица «Order Detail», которая содержит информацию о конкретных купленных билетах.

ID Order: ссылается на суррогатный ключ таблицы «Order».
Item: номер позиции (билета) внутри заказа.
Поля ID Order и Item вместе образуют первичный ключ.
Чтобы указать конкретное место, добавляем поле ID Place. Это внешний ключ к таблице «SitPlace». Протягиваем соответствующую связь.

В итоге мы спроектировали схему, охватывающую связи «многие ко многим», «один ко многим», «один к одному», а также различные типы ключей и категориальное разделение.

Управление базой данных: бекап и восстановление

По окончании проектирования важно уметь сохранять результат.

Создание резервной копии (Backup): В контекстном меню базы данных нужно выбрать Tasks → Backup. В настройках важен режим Full, который выгружает и схему, и данные целиком в один файл.
Восстановление (Restore): Если база данных удалена, через контекстное меню папки Databases выбираем Restore Database. Указываем источник — устройство, и находим наш файл бекапа. Система восстановит все таблицы и диаграммы.

На этом этапе проектирование схемы завершено. Однако логика работы приложения требует программной проверки согласованности данных, что будет рассмотрено в дальнейшем.

Краткие итоги

Последовательно выстроенная схема данных демонстрирует путь от абстрактной задачи к физической модели. Изначальная потребность фиксировать расписание сеансов привела к появлению таблицы, агрегирующей несколько измерений: время, место, продукт (фильм) и его атрибут (формат). Сложность связи «многие ко многим» между фильмами и форматами была корректно разрешена через промежуточную сущность, что позволило создать гибкое расписание.

Моделирование персонала выявило важный архитектурный принцип: не все атрибуты сущности одинаково релевантны для всех её экземпляров. Вместо создания избыточной таблицы с множеством необязательных полей было применено категориальное разделение. Использование отношения «один к одному» с наследованием первичного ключа позволило выделить кассиров, сохранив общую целостность данных о сотрудниках.

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

Финальная стадия проектирования неразрывно связана с эксплуатацией. Демонстрация полного цикла резервного копирования и восстановления — это не просто техническая инструкция, а иллюстрация того, что созданная модель является самодостаточным и восстанавливаемым артефактом. Понимание того, что спроектированная схема — это лишь фундамент, закладывает основу для следующего этапа — программирования бизнес-логики и проверок ограничений, которые не всегда можно выразить декларативно.
Проектирование таблиц расписания и должностей

Начинаем с ключевой сущности — «Расписание». Для идентификации сеанса нужно знать дату и время (StartDate, тип DateTime), зал (ID Hall, int), фильм (ID Film, int) и формат (ID Format, int). Все четыре поля вместе образуют составной первичный ключ. Поля фильма и формата вместе ссылаются на таблицу-пересечение «Фильм-Формат», разрешая связь «многие ко многим».

Далее создаём справочник должностей «JobList» с полями: идентификатор (ID), название (Job Title, varchar) и необязательное поле для комментариев (Comment).

Моделирование сотрудников и категориальное разделение

Создаём таблицу сотрудников «Person». Её первичный ключ — поле Personal Number (табельный номер, int). Остальные атрибуты включают имя, фамилию (varchar(30)), дату рождения (date), номер паспорта (int) и внешний ключ Job Title ID для связи с должностью.

В процессе продажи билетов участвуют исключительно кассиры. Для выделения специфичных именно для них атрибутов применяется категориальное разделение. Создаётся отдельная таблица «Cashier». Её первичный ключ полностью совпадает с ключом родительской таблицы Person (Personal Number). Таким образом, между ними автоматически формируется связь «один к одному». В таблицу кассиров добавляется уникальный атрибут — номер кассы (Cash Register Number). Попадание записи в Cashier однозначно определяет сотрудника как кассира.

Заказы и их детализация

Моделируем факт покупки билетов через таблицу «Order». Её задача — зафиксировать, кто, когда и на какой сеанс купил билеты. Из таблицы «Расписание» сюда копируются поля для идентификации сеанса. Добавляются два новых поля: Order Date (дата заказа) и ID Person (ссылка на кассира из таблицы Cashier).
Попытка использовать эту группу полей как первичный ключ приводит к созданию неоправданно сложного составного ключа из шести частей. Для упрощения вводится суррогатный ключ — поле ID, которое назначается единственным первичным ключом. Это радикально упрощает ссылки на заказ из других таблиц.

Для хранения информации о каждом отдельном билете создаётся таблица «Order Detail». В ней фиксируется, какие конкретно места были куплены в рамках одного заказа. Первичный ключ здесь — составной: он включает ID Order (ссылку на заказ) и Item (порядковый номер билета внутри заказа). Ссылка на конкретное место осуществляется через внешний ключ ID Place к таблице SitPlace. Так реализуется логика «один чек — много билетов».

Резервное копирование и заключение

Созданная схема охватывает основные типы связей: «многие ко многим», «один ко многим», «один к одному», а также различные подходы к выбору ключей. Однако структура таблиц не гарантирует полную непротиворечивость бизнес-логики. Например, схема может позволить назначить сеанс в зале, который технически не поддерживает выбранный формат показа. Такие проверки требуют программной обработки.

В завершение рассматривается процесс резервного копирования. Команда Backup (через Tasks → Backup) в режиме Full создаёт полную копию и схемы, и данных. Процедура Restore позволяет полностью восстановить удалённую базу данных из бекап-файла. Главное условие для восстановления — отсутствие активных подключений к базе на момент операции.

Выводы

1. Таблица расписания является связующим звеном между сущностями фильма, формата и зала.
2. Составные первичные ключи идеально подходят для моделирования пересечений «многие ко многим».
3. Категориальное разделение позволяет добавлять уникальные атрибуты подтипам сущностей без раздувания основной таблицы.
4. Связь «один к одному» автоматически образуется при полном совпадении первичных ключей в двух таблицах.
5. Длинные составные ключи (более 3–4 полей) усложняют разработку, поэтому для них вводят суррогатные идентификаторы.
6. Суррогатный ключ заменяет естественный составной ключ и становится единственным первичным ключом таблицы.
7. Таблица заказов фиксирует факт транзакции, не детализируя её содержимое.
8. Детализация заказа позволяет привязать каждый отдельный билет к конкретному месту в зале.
9. Ссылочная целостность гарантирует, что не будет продан билет на несуществующее место.
10. Полное резервное копирование (Full Backup) сохраняет и данные, и структуру базы.
11. Восстановление из бекапа требует предварительного разрыва активных соединений с базой данных.
12. Программные проверки (триггеры, процедуры) необходимы для контроля бизнес-правил, не заложенных в структуру таблиц.

Вопросы для самопроверки

1. Почему для хранения сеанса требуется ссылаться на сущность пересечения «Фильм-Формат», а не на фильм и формат по отдельности?
2. Каким образом обеспечивается связь «многие ко многим» на уровне физической модели базы данных?
3. В чем заключается принцип категориального разделения и для решения какой задачи он был применён?
4. Какое условие должно выполняться для первичных ключей, чтобы связь между таблицами автоматически стала «один к одному»?
5. Назовите основной недостаток использования длинного составного первичного ключа в таблице заказов.
6. Что такое суррогатный ключ и зачем он был введён в таблице Order?
7. Какую информацию хранит таблица «Order Detail» и как она связана с основным заказом?
8. Можно ли на основе данных таблицы Order узнать, кто из сотрудников оформил продажу?
9. Почему поле Cash Register Number было вынесено в отдельную таблицу, а не добавлено в общую таблицу Person?
10. В чем разница между полным (Full) и разностным (Differential) резервным копированием с точки зрения конечного файла?
11. Почему при попытке удалить базу данных может потребоваться установка галочки «Close existing connections»?
Вернуться к учебному плану