Слабые сущности и идентификаторы
Некоторые сущности не имеют смысла сами по себе и не могут быть идентифицированы без «родителя». Разберём слабые сущности и их ключи.
Слабая сущность — тип сущности, который не имеет собственного достаточного ключа и однозначно идентифицируется только в комбинации с ключом другой (сильной) сущности-владельца.
Идентифицирующие и неидентифицирующие связи
Полезно ввести парное понятие. Связь, по которой строится ключ слабой сущности, называют идентифицирующей: она не просто соединяет сущности, а участвует в идентификации зависимой. Все прочие связи — неидентифицирующие: они выражают ассоциацию, но не входят в ключ. Например, связь «строка заказа принадлежит заказу» идентифицирующая (без заказа строку не опознать), а связь «строка заказа ссылается на товар» — неидентифицирующая (товар лишь уточняет, что именно в строке, но ключ строки от товара не зависит). Это различие напрямую отражается в схеме: внешний ключ по идентифицирующей связи входит в первичный ключ зависимой таблицы, а по неидентифицирующей — остаётся обычным внешним ключом вне первичного ключа. Умение различать эти два типа связей помогает безошибочно собирать составной ключ слабой сущности.
Зачем выделять слабые сущности
Не всё в предметной области существует независимо. Строка заказа («2 книги») бессмысленна без самого заказа. Помещение («комната 305») неоднозначно без здания — в другом здании есть своя комната 305. Платёж по договору не идентифицируется без договора. Такие сущности нельзя проектировать как обычные: у них нет собственного полного ключа, и их жизнь привязана к владельцу. Чтобы не наделать ошибок, их выделяют в особую категорию — слабые сущности.
Ещё примеры слабых сущностей
Чтобы понятие закрепилось, рассмотрим несколько случаев из разных предметных областей. Экземпляр книги в библиотеке: у книги (издания) есть ISBN — сильная сущность; а конкретный физический экземпляр на полке идентифицируется лишь номером внутри этого издания («книга такая-то, экземпляр №3») — слабая сущность. Зависимый член семьи сотрудника для страховки: «ребёнок Иванова по имени Петя» — без сотрудника этот факт не существует и не идентифицируется. Комната в здании: «комната 305» однозначна только вместе со зданием. Платёж по кредиту: «третий платёж по договору №77». Общий признак во всех случаях один: объект осмыслен только в контексте родителя, и его «номер» уникален лишь внутри родителя. Научившись узнавать этот паттерн, вы перестанете либо раздувать такие объекты до самостоятельных сущностей с искусственной глобальной уникальностью, либо, наоборот, терять их, впихивая в родителя.
Сильные и слабые сущности
Сильная (независимая) сущность имеет собственный ключ и существует сама по себе: Клиент, Книга, Здание. Слабая (зависимая) сущность такого ключа не имеет и идентифицируется лишь вместе с владельцем. На ER-диаграмме слабую сущность рисуют двойным прямоугольником, а связь с владельцем — двойным ромбом (идентифицирующая связь).
| Признак | Сильная | Слабая |
| Собственный полный ключ | есть | нет |
| Существование | независимое | зависит от владельца |
| Идентификация | сама по себе | только с ключом владельца |
Зачем вообще выделять слабые сущности отдельно
Можно спросить: если слабую сущность всё равно реализуем таблицей с составным ключом, зачем городить отдельную теорию? Затем, что распознавание слабости меняет проектные решения. Во-первых, оно подсказывает правильный ключ: не искать у строки заказа собственный глобальный идентификатор, а строить ключ из владельца и частичного ключа. Во-вторых, оно диктует политику удаления (каскад). В-третьих, оно влияет на обязательность участия: слабая сущность всегда обязательно участвует в идентифицирующей связи — без владельца её просто нет, значит, внешний ключ на владельца не может быть NULL. Пропустив анализ на слабость, легко получить схему, где строки заказа имеют бессмысленный собственный ключ, переживают удаление заказа и допускают NULL вместо ссылки на родителя. Так что выделение слабых сущностей — не педантизм, а способ принять сразу несколько верных решений.
Частичный ключ и идентифицирующая связь
У слабой сущности есть частичный (дискриминирующий) ключ — атрибут, который различает её экземпляры в пределах одного владельца, но не глобально. Номер строки внутри заказа различает позиции этого заказа, но в другом заказе есть своя строка с тем же номером. Идентифицирующая связь — это связь слабой сущности с владельцем, по которой и достраивается полный ключ.
Полный (первичный) ключ слабой сущности = ключ владельца + частичный ключ. Для строки заказа это (order_id, line_no): номер заказа плюс номер строки. Именно эта комбинация уникальна глобально.
Перевод слабой сущности в таблицу
Правило перевода логично вытекает из определения: таблица слабой сущности получает внешний ключ на владельца, а её первичный ключ составной — из этого внешнего ключа и частичного ключа. Обычно добавляют ON DELETE CASCADE: удалили владельца — удалились и зависимые строки, ведь без владельца они бессмысленны.
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
data TEXT
);
-- слабая сущность "строка заказа": нет смысла без заказа
CREATE TABLE order_lines (
order_id INTEGER REFERENCES orders(id) ON DELETE CASCADE, -- ключ владельца
line_no INTEGER, -- частичный ключ
tovar TEXT,
qty INTEGER,
PRIMARY KEY (order_id, line_no) -- составной ключ = владелец + частичный ключ
);
INSERT INTO orders VALUES (100,'2025-01-10'),(101,'2025-01-11');
INSERT INTO order_lines VALUES (100,1,'Книга',2),(100,2,'Кружка',1),(101,1,'Лампа',1);
-- line_no = 1 встречается в обоих заказах — но пара (order_id, line_no) уникальна
SELECT order_id, line_no, tovar FROM order_lines ORDER BY order_id, line_no;
Вывод: строки (100,1,Книга), (100,2,Кружка), (101,1,Лампа). Обратите внимание: line_no = 1 есть и у заказа 100, и у заказа 101 — частичный ключ сам по себе не уникален, а вот пара с order_id уникальна. Это и есть суть слабой сущности.
Слабая сущность или связующая таблица?
Эти две конструкции легко спутать, ведь обе дают таблицу с составным ключом из внешних ключей. Разница в смысле. Связующая таблица (M:N) соединяет две самостоятельные сущности (заказ и товар существуют независимо). Слабая сущность зависит от одного владельца и без него не существует (строка заказа — это часть заказа, а не отдельный объект). Если зависимый объект имеет собственные атрибуты и порядковый номер внутри родителя — это слабая сущность.
Каскадное удаление и логика существования
Каскадное удаление слабых сущностей — не просто техническое удобство, а отражение их природы. Раз слабая сущность не существует без владельца, удаление владельца обязано повлечь удаление зависимых строк: иначе они превратятся в бессмыслицу — строки заказа, ссылающиеся на несуществующий заказ. Сравните это с обычной (сильной) сущностью: удалив категорию товаров, мы не обязаны удалять сами товары — они существуют независимо, им можно просто обнулить ссылку на категорию (SET NULL). Разница в политике удаления прямо вытекает из того, слабая сущность перед нами или сильная. Поэтому, выбирая ON DELETE CASCADE против SET NULL, по сути отвечают на вопрос: «может ли зависимый объект пережить своего родителя?». Для слабой сущности ответ всегда «нет» — отсюда каскад.
Суррогатные ключи как альтернатива
На практике вместо составного естественного ключа слабой сущности часто вводят суррогатный id (автоинкремент), а связь с владельцем оставляют обычным внешним ключом. Это упрощает ссылки из других таблиц. Но концептуально сущность остаётся слабой: суррогатный ключ — лишь техническое удобство, а смысловая зависимость от владельца никуда не девается, и каскадное удаление по-прежнему уместно.
Типичные ошибки
- Глобально уникальный ключ для слабой сущности. Делают
line_noуникальным по всей таблице — и нельзя иметь строку №1 в каждом заказе. - Забыли ключ владельца в первичном ключе. Без
order_idв составном ключе строки разных заказов конфликтуют. - Нет каскадного удаления. Удалили заказ — остались «осиротевшие» строки, ссылающиеся в никуда.
- Путают слабую сущность со связующей таблицей. Разный смысл: зависимость от одного владельца против связи двух независимых сущностей.
Итог
- Слабая сущность не имеет собственного полного ключа и идентифицируется только вместе с владельцем.
- Частичный ключ различает экземпляры внутри одного владельца; полный ключ = ключ владельца + частичный ключ.
- В таблице это составной первичный ключ из внешнего ключа на владельца и частичного ключа, обычно с каскадным удалением.
- Слабая сущность отличается от связующей таблицы: зависимость от одного владельца, а не связь двух независимых сущностей.