Забезпечення обмежень «дві таблиці»


10

У мене виникли проблеми з моделюванням електричної схеми в SQL. Я хотів би захопити цю структуру

  part ←────────── pin
                   
part_inst ←───── pin_inst

де "inst" - "екземпляр".

Наприклад, у мене може бути як partпідсилювач LM358 з pins 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
);

Основна проблема з цією схемою є те , що pin_instможе бути прив'язана до part_instз , part_id=1але його pinмає 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)як основний ключ.
ypercubeᵀᴹ

Дві речі: (а) не дає 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT і VCC приводити 11-контактні екземпляри? (b) Я не отримую вашої початкової схеми. Не можна шпильку використовувати в більш ніж одній частині? Вам потрібно зв’язок NN між шпилькою та частиною, а не 1-N.
Маркус Юній Брут

@ user34332: (a) Цифри є частиною імен. Наприклад, "2OUT" - це один штифт. Ось схематичний креслення з чіпа я говорю в цьому питанні. (б) Я не згоден. Звичайно, дві частини можуть мати штифт VCC (позитивна напруга живлення, "напруга [у] загального колектора"), але вони логічно різні штифти. Наприклад, один штифт VCC може малювати 500 мкА, а інший 250 мкА.
Сніжок

@Snowball Це допоможе іншим зрозуміти вашу схему, якби ви додали SQL-Fiddle із зразковими даними.
ypercubeᵀᴹ

Відповіді:


13

Мінімальне рішення

Одним радикальним рішенням може бути pin_instповне видалення :

  part ←────────── pin
                   
part_inst ←───── pin_inst

У вашому запитанні немає нічого, що б підказало, що вам справді потрібна надмірна таблиця. Для pins, пов'язаного з a part_inst, подивіться pins на асоційоване part.

Це спростило б код:

create table part (    -- using singular terms for table names
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part
);

Але ваш коментар дав зрозуміти, що ми не підемо з цього ...

Альтернатива, якщо pin_instце потрібно

У тому числі, part_idяк і у вас, це найпростіше рішення з обмеженнями зовнішніх ключів. Не можна посилатись на таблицю «дві таблиці» з обмеженнями зовнішніх ключів .

Але ви можете принаймні зробити без «забруднення» первинних ключів. Додайте UNIQUEобмеження .

create table part (
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, pin_id)         -- note sequence of columns
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, part_inst_id)
);
create table pin_inst (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,
    pin_id bigint not null,
    part_id bigint not,
    foreign key (part_id, pin_id) references pin,
    foreign key (part_id, part_inst_id) references part_inst
);

Я ставлю part_idперше місце в унікальних обмеженнях. Це не має значення для референтної цілісності, але має значення для продуктивності. Первинні ключі вже реалізують індекси для pk стовпців. Інший стовпець краще мати спочатку в індексах багатокольонок, що реалізують унікальні обмеження. Деталі під цими пов'язаними питаннями:

Пов’язані запитання щодо SO:

Альтернатива з пусками

Ви можете вдатися до тригерних функцій, які є більш гнучкими, але трохи складнішими і схильними до помилок і трохи менш суворими. Вигода: ви могли б обійтися part_inst.part_idі без pin.part_id...


У цьому розділі є кілька додаткових стовпців pin_insts, але я їх опустив з-за читабельності ("Ігнорування полів даних, [...]"). Наприклад, знак pin_instможе бути позначений як вхід або вихід.
Сніжок

@Snowball: Легко було б правдою. Я трохи розширив ваше рішення.
Ервін Брандштеттер

2
Ваша друга пропозиція добре працює для моєї ситуації. Я не знав, що іноземний ключ може посилатися на щось інше, ніж на первинний ключ.
Сніжок
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.