Learning Platform
Глоссарий Troubleshooting
Урок 04.03 · 20 мин
Начальный
er-modelingweak-entitygeneralizationsubtype

Weak vs strong entities, subtypes и supertypes

Базовых трёх элементов — сущность, атрибут, связь — достаточно для простых моделей. Но реальные предметные области сложнее, и ER-моделирование даёт две продвинутые конструкции для их точного описания. Первая — различие слабых и сильных сущностей: что делать с сущностью, у которой нет собственного идентификатора. Вторая — обобщение и специализация (supertype/subtype): что делать, когда сущности похожи, но не одинаковы.

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

Strong entity — сильная сущность

Сильная (регулярная) сущность (strong entity) — это сущность, которая имеет собственный ключевой атрибут и существует независимо от других сущностей. Большинство сущностей, с которыми мы работали, — сильные: Клиент, Товар, Заказ. У Клиента есть свой customer_id, и клиент существует сам по себе, не зависит от существования других сущностей.

Сильная сущность — это норма. Если ничего особенного про сущность не сказано, она сильная.

Weak entity — слабая сущность

Слабая сущность (weak entity) — это сущность, которая не имеет собственного достаточного ключевого атрибута и не может быть однозначно идентифицирована без другой сущности. Слабая сущность зависит от сущности-владельца (owner / identifying entity).

Разберём на примере. Возьмём сущность «Позиция заказа» (order line) — конкретная строка внутри заказа: товар, количество, цена. Можно ли идентифицировать позицию заказа сама по себе? Номер позиции «1» бессмыслен в отрыве от заказа — позиция «1» есть в каждом заказе. Позиция уникальна только в паре «заказ + номер позиции». Позиция заказа — слабая сущность; её владелец — Заказ.

Другой пример: «Комната» в гостинице. Комната «305» сама по себе не уникальна — комната «305» есть во многих гостиницах. Комната уникальна только как «гостиница + номер комнаты». Комната — слабая сущность, владелец — Гостиница.

У слабой сущности два ключевых понятия:

  • Идентифицирующая связь (identifying relationship) — связь со владельцем, через которую слабая сущность получает идентификацию. Слабая сущность не существует без этой связи.
  • Частичный ключ / дискриминатор (partial key, discriminator) — атрибут, который различает экземпляры слабой сущности в пределах одного владельца. Для позиции заказа это номер позиции; для комнаты — номер комнаты. Сам по себе частичный ключ не уникален.

Полный идентификатор слабой сущности = ключ владельца + частичный ключ. Для позиции заказа: order_id (ключ владельца) + line_number (частичный ключ).

Слабая сущность получает идентификацию от владельца
Заказ (владелец)Сильная сущность-владелец. Имеет собственный ключ order_id. Существует независимо.
идентифицирующая связь
Позиция заказа (слабая)Слабая сущность. Свой частичный ключ line_number не уникален. Полный идентификатор — order_id + line_number.

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

CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY,
    order_date DATE NOT NULL
);

-- Слабая сущность: PK составной — ключ владельца + частичный ключ
CREATE TABLE order_lines (
    order_id    BIGINT  NOT NULL REFERENCES orders(order_id),
    line_number INTEGER NOT NULL,
    product_id  BIGINT  NOT NULL,
    quantity    INTEGER NOT NULL CHECK (quantity > 0),
    PRIMARY KEY (order_id, line_number)
);
-- line_number сам по себе не уникален; уникальна пара (order_id, line_number)
NOTE

Различие слабой и сильной сущности тесно связано с identifying и non-identifying связями, которые подробно разбираются в модуле про связи и кардинальность. Слабая сущность всегда участвует в identifying-связи со своим владельцем — внешний ключ на владельца входит в её первичный ключ. Здесь достаточно понимать саму идею: некоторые сущности не могут быть идентифицированы без «родителя».

На практике многозначные атрибуты и слабые сущности часто пересекаются. Помните customer_phones из прошлого урока? Телефон клиента — это, по сути, слабая сущность: телефон идентифицируется только в паре «клиент + номер». Многозначный атрибут, вынесенный в отдельную таблицу, нередко и есть слабая сущность.

Generalization и specialization

Вторая продвинутая конструкция решает другую задачу: что делать, когда сущности похожи, но не идентичны.

Представим систему компании с сотрудниками. Есть штатные сотрудники и подрядчики. У них много общего: имя, контакты, табельный номер. Но есть и различия: у штатного есть оклад и отпускные дни, у подрядчика — ставка за час и срок контракта. Как это смоделировать?

Здесь работает обобщение/специализация (generalization/specialization) — иерархия supertype/subtype.

  • Supertype (надтип, родительская сущность) — общая сущность, содержащая атрибуты, общие для всех. В примере — «Сотрудник» с атрибутами имя, контакты, табельный номер.
  • Subtype (подтип, дочерняя сущность) — специализированная сущность, содержащая атрибуты, специфичные для своего вида. В примере — «Штатный сотрудник» (оклад, отпуск) и «Подрядчик» (ставка, срок контракта).

Подтип наследует все атрибуты надтипа и добавляет свои. Штатный сотрудник — это и есть Сотрудник, плюс оклад и отпуск.

Иерархия supertype и subtypes
Supertype: СотрудникНадтип — общая сущность. Содержит атрибуты, общие для всех видов: имя, контакты, табельный номер.
специализируется на
Subtypes: Штатный / ПодрядчикПодтипы — специализированные сущности. Наследуют атрибуты надтипа и добавляют свои: оклад и отпуск, либо ставка и срок контракта.

Направление имеет названия: движение от подтипов к надтипу (выделение общего) — это обобщение (generalization); движение от надтипа к подтипам (выделение различий) — это специализация (specialization). Это две стороны одного отношения.

Два свойства иерархии supertype/subtype

Иерархию уточняют два свойства — они отвечают на важные вопросы о подтипах.

Disjoint vs overlapping (непересекающиеся или пересекающиеся). Может ли один экземпляр принадлежать сразу нескольким подтипам?

  • Disjoint (непересекающиеся) — экземпляр принадлежит ровно одному подтипу. Сотрудник либо штатный, либо подрядчик, но не оба сразу.
  • Overlapping (пересекающиеся) — экземпляр может принадлежать нескольким подтипам. Например, в университете человек может быть одновременно и Студентом, и Преподавателем.

Total vs partial (полное или частичное участие). Обязан ли каждый экземпляр надтипа принадлежать какому-то подтипу?

  • Total (полное участие) — каждый экземпляр надтипа обязательно относится к одному из подтипов. Каждый Сотрудник — либо штатный, либо подрядчик, третьего не дано.
  • Partial (частичное участие) — экземпляр надтипа может не относиться ни к одному подтипу. Например, если кроме штатных и подрядчиков бывают сотрудники, чей тип ещё не определён.

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

КомбинацияЧто означаетПример
Disjoint + totalРовно один подтип, обязательноСотрудник: штатный xor подрядчик
Disjoint + partialНе более одного подтипаСотрудник: штатный, подрядчик или «пока никто»
Overlapping + totalХотя бы один подтип, можно несколькоУчастник вуза: студент и/или преподаватель
Overlapping + partialЛюбое число подтипов, включая нольГибкая классификация без обязательности

Как иерархию превращают в таблицы

Иерархию supertype/subtype можно реализовать в реляционной схеме тремя способами — это важное проектное решение.

Способ 1: одна таблица на всё (single table). Все атрибуты надтипа и всех подтипов — в одной таблице, плюс колонка-дискриминатор «тип». Атрибуты неподходящего подтипа в строке остаются NULL (у подрядчика колонка «оклад» пустая). Просто, без соединений, но много NULL.

Способ 2: таблица на каждый подтип (table per subtype). Отдельная таблица на каждый подтип, и каждая содержит и общие атрибуты, и свои. Надтип отдельной таблицей не существует. Нет лишних NULL, но общие данные продублированы по структуре, а запрос «все сотрудники» требует объединения таблиц.

Способ 3: таблица надтипа плюс таблицы подтипов (table per type). Таблица для надтипа с общими атрибутами и отдельные таблицы для каждого подтипа со специфичными атрибутами, связанные с надтипом. Чисто с точки зрения нормализации, но запросы требуют соединений.

Три способа реализации иерархии в таблицах
Single tableОдна таблица на надтип и все подтипы плюс колонка-дискриминатор. Просто, без соединений, но много NULL в неподходящих колонках.
Table per subtypeОтдельная таблица на каждый подтип, каждая с общими и своими атрибутами. Нет NULL, но структура дублируется, запрос 'все' требует UNION.
Table per typeТаблица надтипа с общими атрибутами плюс таблицы подтипов со специфичными, связанные с надтипом. Чисто, но запросы требуют JOIN.
TIP

Нет единственно правильного способа — выбор зависит от данных и запросов. Если подтипы почти не отличаются атрибутами и часто запрашиваются вместе — берите single table. Если подтипы сильно различаются и запрашиваются раздельно — table per subtype. Если важна нормализация и общие атрибуты объёмны — table per type. Это решение physical-уровня, и принимать его надо осознанно, взвесив количество NULL, дублирование и стоимость соединений.

Ограничения как способ зафиксировать вид иерархии в DDL

Попробуй сам

Часть 1, слабые сущности. Возьмите систему многоквартирного дома: есть Дом и есть Квартира. Объясните, почему Квартира — слабая сущность: что является её владельцем, что частичным ключом, из чего состоит её полный идентификатор. Напишите для Дома и Квартиры пару CREATE TABLE с правильным составным первичным ключом у Квартиры.

Часть 2, иерархия. Возьмите сущность «Платёж» в интернет-магазине: бывают платежи картой (есть номер карты, банк) и платежи криптовалютой (есть адрес кошелька, сеть). Постройте иерархию supertype/subtype: что в надтипе, что в подтипах. Определите два свойства — disjoint или overlapping, total или partial — и обоснуйте. Выберите один из трёх способов реализации в таблицах и объясните, почему именно он подходит для платежей.


Проверка знанийKnowledge check
Что такое слабая сущность, чем она отличается от сильной, и как из чего складывается её полный идентификатор? Приведите пример.
ОтветAnswer
Слабая сущность (weak entity) — это сущность, которая не имеет собственного достаточного ключевого атрибута и не может быть однозначно идентифицирована без другой сущности. Сильная (регулярная) сущность, наоборот, имеет собственный ключ и существует независимо — например, Клиент с его customer_id. Слабая сущность зависит от сущности-владельца (owner) и связана с ней идентифицирующей связью (identifying relationship), без которой не существует. У слабой сущности есть частичный ключ (дискриминатор) — атрибут, различающий её экземпляры только в пределах одного владельца; сам по себе он не уникален. Полный идентификатор слабой сущности складывается из ключа владельца плюс частичного ключа. Пример: «Позиция заказа» — слабая сущность, её владелец — Заказ; частичный ключ — номер позиции (line_number), который не уникален сам по себе, потому что позиция «1» есть в каждом заказе; полный идентификатор — пара (order_id, line_number). В реляционной таблице слабая сущность реализуется через составной первичный ключ, включающий внешний ключ на владельца. Другой пример — Комната в гостинице: номер «305» уникален только в паре «гостиница + номер комнаты».

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что является полным идентификатором слабой сущности?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5