Wystąpił problem z modelowaniem schematu elektrycznego w SQL. Struktura, którą chciałbym uchwycić, to
part ←────────── pin
↑ ↑
part_inst ←───── pin_inst
gdzie „inst” jest skrótem od „instancja”.
Na przykład, mogę mieć jako part
wzmacniacz pin
operacyjny LM358 z s 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT i V CC . Mógłbym wtedy umieścić tę część na schemacie, tworząc a part_inst
i 8
pin_inst
s.
Ignorując pola danych, moją pierwszą próbą schematu było
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
);
Głównym problemem związanym z tym schematem jest to, że pin_inst
można go powiązać part_inst
z, part_id=1
ale pin
ma part_id=2
.
Chciałbym uniknąć tego problemu na poziomie bazy danych niż na poziomie aplikacji. Zmodyfikowałem więc moje klucze podstawowe, aby to wymusić. Zmienione linie oznaczyłem za pomocą --
.
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 --
);
Wadę tej metody polega na tym, że zanieczyszcza ona klucze podstawowe: gdziekolwiek się odwołuję part_inst
, muszę śledzić zarówno te, jak
part_inst_id
i part_id
. Czy istnieje inny sposób narzucenia ograniczenia
pin_inst.part_inst.part_id = pin_inst.pin.part_id
bez nadmiernej gadatliwości?
źródło
pin_inst_id
nadmiarowość. Możesz użyć tego(part_inst_id, part_id, pin_id)
jako klucza podstawowego.Odpowiedzi:
Minimalne rozwiązanie
Jednym radykalnym rozwiązaniem może być
pin_inst
całkowite usunięcie :W twoim pytaniu nie ma nic, co sugerowałoby, że faktycznie potrzebujesz zbędnej tabeli. Dla
pin
s powiązanych z apart_inst
spójrz napin
s powiązanychpart
.Uprościłoby to kod do:
Ale twój komentarz wyjaśnił, że nie uciekniemy od tego ...
Alternatywa, jeśli
pin_inst
jest potrzebnaUwzględnienie
part_id
tak jak Ty to najprostsze rozwiązanie z ograniczeniami klucza obcego. Nie można odwoływać się do tabeli „dwie tabele dalej” z ograniczeniami klucza obcego .Ale możesz przynajmniej zrobić bez „zanieczyszczania” kluczy podstawowych. Dodaj
UNIQUE
ograniczenia .Na
part_id
pierwszym miejscu stawiam wyjątkowe ograniczenia. Nie ma to znaczenia dla integralności referencyjnej, ale ma znaczenie dla wydajności. Klucze podstawowe już implementują indeksy dla kolumn pk. Lepiej, aby druga kolumna była pierwsza w indeksach wielokolumnowych implementujących unikalne ograniczenia. Szczegóły w ramach powiązanych pytań:Powiązane pytania dotyczące SO:
Alternatywa z wyzwalaczami
Możesz skorzystać z funkcji wyzwalaczy, które są bardziej elastyczne, ale nieco bardziej skomplikowane, podatne na błędy i nieco mniej surowe. Korzyść: można zrobić bez
part_inst.part_id
ipin.part_id
...źródło
pin_insts
, ale pominąłem je ze względu na czytelność („Ignorowanie pól danych, [...]”). Na przykład, apin_inst
może być oznaczone jako wejście lub wyjście.