Чому для складених зовнішніх ключів потрібне окреме унікальне обмеження?


10

Ось проста таблиця, де записи можуть посилатися на батьківські записи в тій самій таблиці:

CREATE TABLE foo (
    id         SERIAL  PRIMARY KEY,
    parent_id  INT     NULL,
    num        INT     NOT NULL,
    txt        TEXT    NULL,
    FOREIGN KEY (parent_id) REFERENCES foo(id)
);

З додатковою вимогою, що одне з інших значень поля ( num) має бути однаковим між записом батьків та дітей, я подумав, що складений зовнішній ключ повинен зробити трюк. Я змінив останній рядок на

    FOREIGN KEY (parent_id, num) REFERENCES foo(id, num)

і отримано ПОМИЛКА: не існує єдиного відповідного обмеження для заданих ключів для посилається таблиці "foo" .

Я можу легко додати це обмеження, але я не розумію, для чого це потрібно, коли один із посилаються стовпців ( id) вже гарантовано є унікальним? Як я це бачу, нове обмеження було б зайвим.

Відповіді:


11

Це обмеження СУБД - у всіх, наскільки я знаю. І не тільки при додаванні стовпця, але і при перестановці стовпців. Якщо у нас є UNIQUEобмеження (a1, a2), ми не можемо додати FOREIGN KEYцього, REFERENCES (a2, a1)якщо не існує унікального обмеження на те, (a2, a1)що по суті є зайвим.

Не було б страшно важко додати це як особливість:

Коли є UNIQUEобмеження на (a), то будь-який (a, b, c, ..., z)або (b,c, ...a, ...z)комбінація також гарантується UNIQUE.

або узагальнення:

Якщо існує UNIQUEобмеження (a1, a2, ..., aN), (a1, a2, ..., aN, b1, b2, ..., bM)гарантується також будь-яка комбінація чи будь-яка перестановка UNIQUE.

Здається, що його не запитували або не вважали достатньо високим пріоритетом для його реалізації.

Ви завжди можете зробити запит на відповідному каналі щодо функції, яку потрібно реалізувати. Або навіть реалізувати його самостійно, якщо СУБД є відкритим кодом, наприклад Postgres.


Я не впевнений, що це було б досить просто. Що з частковими індексами або значеннями NULL? тощо. NULL все ще може працювати нормально, якщо ви задоволені NULL != NULL. У всякому разі .. :)
Джоїші Бодіо

@JoishiBodio Я не думаю, що Nulls - це проблема. UNIQUE обмеження можуть бути визначені або зведені до нуля стовпці. Типовим є те, що якщо будь-який стовпець містить NULL, обмеження передається і рядок приймається.
ypercubeᵀᴹ

По-друге, проте, якщо a1, a2, ... aN не є нульовими, а b1, b2, bM ми можемо потрапити в проблеми. Але ця функція, безумовно, може бути реалізована для стовпчиків, що не змінюються. Можливо, це хвилює наслідки для ефективності.
ypercubeᵀᴹ

Мені знайоме, UNIQUE INDEXде стовпці NULLABLE.. саме тому я це згадав. :) Але я згоден - у випадку, якщо немає NULL (а також часткового індексу), це, мабуть, досить прямо.
Джоїші Бодіо

5

Іноземні ключі взагалі (не просто композитні) ОБОВ'ЯЗКОВО вказують на УНІКАЛЬНИЙ КЛЮЧ якийсь в іншій таблиці. Якби не вони, цілісність реляційних даних не існувала б.

Це скарги, оскільки, хоча у вас є унікальний ключ (id) .. у вас НЕ є унікальний ключ (id, num) .. Таким чином, що стосується БД, пара (id, num) є не гарантовано бути унікальним. Ми, як люди, можемо зрозуміти, що це буде унікальним, але я впевнений, що було б багато додаткового коду, який вони повинні були б додати, щоб зробити Postgres досить розумним, щоб побачити, що "о, так ... ідентифікатор повинен бути унікальним , тому id, num також має бути унікальним "..

Я був би дуже здивований, якби вони додали цей код, коли все, що вам потрібно зробити, це створити ще один унікальний індекс на двох стовпцях, щоб вирішити проблему.

Щоб було зрозуміло, код, який вони повинні були б додати, був би не просто цим простим випадком ... він мав би обробляти всі випадки, навіть ті, де зовнішній ключ знаходиться на 4+ стовпцях тощо. Я впевнений логіка була б досить складною.

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