Я столкнулся с некоторыми проблемами при моделировании электрической схемы в SQL. Структура, которую я хотел бы захватить,
part ←────────── pin
↑ ↑
part_inst ←───── pin_inst
где «inst» - это сокращение от «instance».
Например, я мог бы иметь в part
качестве операционного усилителя LM358 с pin
s 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT и V CC . Затем я мог бы разместить эту часть на схеме, создавая part_inst
и 8
pin_inst
с.
Игнорируя поля данных, моя первая попытка создания схемы была
create table parts (
part_id bigserial primary key
);
create table pins (
pin_id bigserial primary key,
part_id bigint not null references parts
);
create table part_insts (
part_inst_id bigserial primary key,
part_id bigint not null references parts
);
create table pin_insts (
pin_inst_id bigserial primary key,
part_inst_id bigint not null references part_insts,
pin_id bigint not null references pins
);
Основная проблема с этой схемой заключается в том, что a pin_inst
может быть связано с part_inst
with, part_id=1
но pin
имеет has part_id=2
.
Я хотел бы избежать этой проблемы на уровне базы данных, а не на уровне приложений. Итак, я изменил свои первичные ключи, чтобы обеспечить это. Я пометил измененные строки с помощью --
.
create table parts (
part_id bigserial primary key
);
create table pins (
pin_id bigserial, --
part_id bigint not null references parts,
primary key (pin_id, part_id) --
);
create table part_insts (
part_inst_id bigserial, --
part_id bigint not null references parts,
primary key (part_inst_id, part_id) --
);
create table pin_insts (
pin_inst_id bigserial primary key,
part_inst_id bigint not null, --
pin_id bigint not null, --
part_id bigint not null references parts, --
foreign key (part_inst_id, part_id) references part_insts, --
foreign key (pin_id, part_id) references pins --
);
Мой метод заключается в том, что он загрязняет первичные ключи: везде, где я ссылаюсь на part_inst
, мне нужно отслеживать как
part_inst_id
и, так и part_id
. Есть ли другой способ, как я могу применить ограничение,
pin_inst.part_inst.part_id = pin_inst.pin.part_id
не будучи слишком многословным?
pin_inst_id
избыточность. Вы можете использовать в(part_inst_id, part_id, pin_id)
качестве первичного ключа.Ответы:
Минимальное решение
Одним из радикальных решений может быть
pin_inst
полное удаление :В вашем вопросе нет ничего, что указывало бы на то, что вам действительно нужна избыточная таблица. Для
pin
s, связанных с apart_inst
, посмотрите наpin
s связанныхpart
.Это упростит код до:
Но ваш комментарий дал понять, что нам это не сойдет с рук ...
Альтернатива, если
pin_inst
это необходимоВключение,
part_id
как вы сделали, является самым простым решением с ограничениями внешнего ключа. Вы не можете ссылаться на таблицу «на расстоянии двух таблиц» с ограничениями внешнего ключа .Но вы можете, по крайней мере, обойтись без «загрязнения» первичных ключей. Добавить
UNIQUE
ограничения .Я ставлю на
part_id
первое место в уникальных ограничениях. Это не имеет отношения к ссылочной целостности, но имеет значение для производительности. Первичные ключи уже реализуют индексы для столбцов pk. Лучше иметь другой столбец первым в многоколоночных индексах, реализующих уникальные ограничения. Подробности по этим связанным вопросам:Похожие вопросы по SO:
Альтернатива с триггерами
Вы можете прибегнуть к триггерным функциям, которые являются более гибкими, но более сложными, подверженными ошибкам и менее строгими. Выгода: Вы могли бы обойтись без
part_inst.part_id
иpin.part_id
...источник
pin_insts
, но я опустил их для удобства чтения («Игнорирование полей данных, [...]»). Например, аpin_inst
может быть помечен как вход или выход.