Практическое занятие №3: сущности и связи

1. Мост между миром концепций и реляционных таблиц

Проектирование реляционной схемы — это формализованный процесс трансляции концептуальных сущностей и абстрактных связей в строгие физические таблицы, первичные ключи и внешние ограничения целостности (FOREIGN KEY).

Концептуальный уровень (ER-модель)

  • Сущности (сильные и слабые)
  • Связи (1:1, 1:M, M:N)
  • Атрибуты сущностей и связей
  • Бизнес-правила предметной области

Логический/реляционный уровень

  • Отношения (таблицы реляционной БД)
  • Первичные ключи (PRIMARY KEY)
  • Внешние ключи (FOREIGN KEY)
  • Ассоциативные (связующие) таблицы

2. Правило 1: Отображение сильных сущностей

Сильная (независимая) сущность существует автономно и обладает собственным первичным ключом, не зависящим от других объектов системы (например, Клиент, Актер, Товар, Режиссер).

Алгоритм трансляции сильной сущности:

  1. Создается отдельная реляционная таблица с именем во множественном числе в нижнем регистре (snake_case).
  2. Каждый простой концептуальный атрибут становится именованным столбцом таблицы.
  3. Назначается суррогатный первичный ключ (INT / BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY) либо естественный ключ.
  4. Для естественных бизнес-идентификаторов (ИНН, СНИЛС, телефон, email) создаются ограничения уникальности UNIQUE NOT NULL.

3. Правило 2: Отображение слабых (зависимых) сущностей

Слабая сущность не может существовать без своей сущности-владельца (родителя) и не имеет достаточного первичного ключа для собственной глобальной идентификации (например, Позиция заказа, Абонемент клиента).

Ключевые свойства трансляции

  • Обязательная миграция первичного ключа владельца в виде FOREIGN KEY NOT NULL.
  • Формирование составного первичного ключа: PRIMARY KEY (id_roditelya, nomer_pozicii).
  • Политика жесткого каскадного удаления: ON DELETE CASCADE.

Пример в SQL

CREATE TABLE abonementy (
    id_abonementa INT GENERATED ALWAYS AS IDENTITY,
    id_klienta    INT NOT NULL 
        REFERENCES klienty(id_klienta) 
        ON DELETE CASCADE,
    tip_karty     VARCHAR(50) NOT NULL,
    PRIMARY KEY (id_abonementa)
);

4. Правило 3: Трансляция бинарных связей 1:1

Отношение «Один-к-одному» встречается при разделении частых и редких атрибутов, обеспечении безопасности или связи профиля с корзиной покупок.

Способ А: Внешний ключ с UNIQUE

Внешний ключ помещается в подчиненную таблицу и объявляется уникальным:

CREATE TABLE pasporta (
    id_pasporta INT PRIMARY KEY,
    seriya_nomer VARCHAR(20) NOT NULL UNIQUE,
    id_grazhdanina INT NOT NULL UNIQUE
        REFERENCES grazhdane(id)
);

Способ Б: Совмещение PK и FK

Первичный ключ дочерней таблицы одновременно является внешним ключом (идеально для Корзины):

CREATE TABLE korziny (
    id_pokupatelya INT PRIMARY KEY 
        REFERENCES pokupateli(id)
        ON DELETE CASCADE,
    obnovleno TIMESTAMP NOT NULL
);

5. Правило 4: Трансляция бинарных связей 1:M

Фундаментальное правило реляционной модели: Внешний ключ (FK) ВСЕГДА мигрирует в таблицу, находящуюся на стороне «Многие» (M)!

Родительская таблица (сторона 1)

Содержит первичный ключ и не знает о дочерних строках:

CREATE TABLE rezhissery (
    id_rezhissera INT PRIMARY KEY,
    fio VARCHAR(120) NOT NULL
);

Дочерняя таблица (сторона M)

Получает ссылку на родителя:

CREATE TABLE filmy (
    id_filma INT PRIMARY KEY,
    nazvanie VARCHAR(150) NOT NULL,
    id_rezhissera INT NOT NULL 
        REFERENCES rezhissery(id_rezhissera)
        ON DELETE RESTRICT
);

⚠️ Типовая ошибка: Попытка поместить ID фильма в строку режиссера — это ограничит режиссера ровно одним фильмом!

6. Дилемма связи «Многие-ко-многим» (M:N)

В концептуальной модели связь M:N естественна: Актеры снимаются во множестве Фильмов, Заказы содержат множество Блюд.

Почему M:N нельзя связать напрямую?

  • В реляционной таблице строка пересечения строки и колонки обязана быть атомарной (1NF).
  • Нельзя хранить список внешних ключей "1, 5, 23" в ячейке.
  • Внешний ключ может ссылаться ровно на одну строку родителя.

Решение: Декомпозиция

Отношение M:N строго декомпозируется на две связи 1:M через введение третьей — промежуточной (ассоциативной) таблицы.

[Фильмы] 1 ─── M [Фильм_Актер] M ─── 1 [Актеры]

7. Анатомия ассоциативной таблицы

Ассоциативная таблица (Junction / Bridge table) объединяет сущности и хранит специфические атрибуты пересечения:

CREATE TABLE film_akter (
    id_filma       INT NOT NULL REFERENCES filmy(id_filma) ON DELETE CASCADE,
    id_aktera      INT NOT NULL REFERENCES aktery(id_aktera) ON DELETE RESTRICT,
    rol_personazh  VARCHAR(120) NOT NULL,
    is_glavnaya    BOOLEAN NOT NULL DEFAULT FALSE,
    gonorar        NUMERIC(12,2) CHECK (gonorar >= 0),
    PRIMARY KEY (id_filma, id_aktera, rol_personazh)
);

1. Внешние ключи

Две колонки ссылаются на первичные ключи исходных сущностей.

2. Составной PK

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

3. Атрибуты связи

Поля, которые не принадлежат ни фильму отдельно, ни актеру отдельно.

8. Атрибуты связи: Где хранить цену и роль?

Критический вопрос проектировщика: Существует ли данный атрибут вне факта взаимодействия двух сущностей?

Кейс «Доставка еды»

Где хранить цену блюда?

  • В таблице blyuda — хранится текущая цена в меню.
  • В таблице poziciya_zakaza — хранится цена на момент заказа!
  • Если не сохранить цену в строке заказа, при изменении меню изменятся суммы всех закрытых чеков в архиве!

Кейс «Кастинг фильмов»

Где хранить роль персонажа?

  • У актера роли нет (он играет сотни ролей за жизнь).
  • У фильма одной роли нет (в фильме десятки персонажей).
  • Роль привязана строго к связке «Конкретный Актер в Конкретном Фильме».

9. Ссылочная целостность: Выбор каскадных правил

Политика Механизм действия Сфера применения
ON DELETE RESTRICT Блокирует удаление родителя при наличии дочерних строк. Мастер-справочники, клиенты, авторы, врачи, товары (защита архивов).
ON DELETE CASCADE Автоматически уничтожает дочерние строки вслед за родителем. Связующие таблицы M:N, строки корзины, вложенные позиции черновика заказа.
ON DELETE SET NULL Устанавливает FK в NULL при удалении родительской записи. Необязательные связи (промокод со скидкой, куратор группы).

10. Составной PK vs Суррогатный ID в связующих таблицах

Подход 1: Чистый составной PK

PRIMARY KEY (id_zakaza, id_blyuda)

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

Минусы: Сложнее ссылаться из других таблиц (если потребуются внешние ключи на саму строку позиции).

Подход 2: Суррогатный ID + UNIQUE

id_pozicii BIGINT PRIMARY KEY,
UNIQUE (id_zakaza, id_blyuda)

Плюсы: Простой компактный идентификатор для дочерних спецификаций и REST API.

Требование: Ограничение UNIQUE на связку внешних ключей СТРОГО обязательно!

11. 5-шаговый алгоритм трансляции модели

  1. Шаг 1. Сформировать таблицы для всех сильных сущностей, назначить суррогатные PK и UNIQUE-ограничения.
  2. Шаг 2. Реализовать бинарные связи 1:M, добавив FOREIGN KEY в таблицу на стороне «Многие».
  3. Шаг 3. Декомпозировать все связи M:N: создать ассоциативные таблицы, перенести внешние ключи и атрибуты взаимодействия.
  4. Шаг 4. Сформировать таблицы слабых сущностей со ссылкой на владельца и составным ключом.
  5. Шаг 5. Настроить правила каскадирования (RESTRICT / CASCADE) и проверить совпадение типов FK и PK.

12. Топ-3 ошибок студентов при трансляции

1. Потерянная таблица M:N

Студент пытается записать список кодов в текстовую строку VARCHAR. База теряет атомарность, индексы перестают работать, поиск парализован.

2. Несоответствие типов

Первичный ключ родителя объявлен как BIGINT, а внешний ключ дочерней таблицы — как INT или VARCHAR. СУБД возвращает ошибку DDL.

3. Утечка атрибута связи

Цена чека помещена в общее меню блюд, а роль персонажа — в анкету актера. Нарушается логика предметной области и история операций.

13. Чек-лист проверки перед отправкой решения

Культовый веб-комикс xkcd: Exploits of a Mom
Тематический интернет-мем: «Exploits of a Mom» (культовый веб-комикс про «Little Bobby Tables», xkcd #327).
Автор: Randall Munroe. Первоисточник: xkcd.com/327.
Лицензия: Creative Commons Attribution-NonCommercial 2.5 Generic (CC BY-NC 2.5).
Связь с темой занятия: Проектируя таблицы, первичные ключи и внешние связи реляционной БД, инженер обязан закладывать строгие ограничения целостности и типизацию. Если связи и поля не защищены, небрежное заполнение строковых полей способно разрушить схему таблиц всей организации (Robert'); DROP TABLE Students;--).
1 / 15