Можно ли определить внешний ключ, поля которого принадлежат разным, но связанным таблицам?

#sql #sql-server #sql-server-2008 #sql-server-2008-r2

#sql #sql-сервер #sql-server-2008 #sql-server-2008-r2

Вопрос:

Дано четыре таблицы:

 CREATE TABLE LIST_A (
    A INT,
    PRIMARY KEY (A)
)

CREATE TABLE LIST_B (
    A INT,
    B INT,
    PRIMARY KEY (A, B),
    FOREIGN KEY (A) REFERENCES LIST_A (A)
)

CREATE TABLE LIST_C (
    C INT,
    A INT,
    PRIMARY KEY (C),
    FOREIGN KEY (A) REFERENCES LIST_A (A)
)

CREATE TABLE LIST_D (
    C INT,
    D INT,
    B INT,
    PRIMARY KEY (C, D),
    FOREIGN KEY (C) REFERENCES LIST_C (C)
)
 

Я хочу добавить еще одно ограничение: учитывая строку в LIST_D , чей первичный (C0,D0) ключ, и его родительскую строку в LIST_C , чей первичный ключ C0 , пара (LIST_C.A, LIST_D.B) должна ссылаться LIST_B (A, B) . Как мне реализовать это в SQL Server 2008 R2?

Комментарии:

1. У вас не может быть внешнего ключа, составленного из столбцов из двух разных таблиц. Внешний ключ всегда является связующим звеном между одной таблицей и другой, а не между двумя (или более) таблицами на одном конце и другой на другом конце

2. @marc_s: Я не знаю, как выразить это простыми словами, поэтому я просто надеюсь, что смогу прояснить свою точку зрения. Думайте о LIST_A и LIST_C как о таблицах «заголовков», а о LIST_B и LIST_D как об их соответствующих «деталях». Я хочу, чтобы каждый C заголовок был связан с A заголовком; и я также хочу, чтобы каждая D деталь, связанная с конкретным C заголовком, была связана с B деталью, связанной с тем же A заголовком C , с которым связан заголовок.

3. Неважно, как вы это говорите: у вас не может быть внешнего ключа, состоящего из двух столбцов из двух разных таблиц…

4. @marc_s: Есть ли альтернативный способ выразить идею, которую я пытаюсь смоделировать? Я знаю, что мог бы заставить его работать следующим неэлегантным способом: пусть A будет частью LIST_C первичного ключа. Затем, чтобы сохранить связь между LIST_C и LIST_D , добавьте A в качестве поля LIST_D . Наконец, чтобы сохранить уникальность C in LIST_C , добавьте UNIQUE ограничение на это поле. // Но это явно взлом дизайна, и, учитывая масштаб моего проекта, я должен поддерживать его в чистоте, по крайней мере, на уровне дизайна.

Ответ №1:

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

В зависимости от конкретной проблемы, которую вы пытаетесь решить (проверка данных при вводе, каскадные удаления и т. Д.), И гибкости, которой вы обладаете для их решения (возможность или невозможность изменять структуру данных), вы можете реализовать логические ограничения с помощью триггеров. Мы используем этот подход в тех случаях, когда нам просто нужно перехватить граничные условия, которые должны возникать редко, если вообще когда-либо.

Если триггеров недостаточно для вашей ситуации и требуются внешние ключи, то единственный оставшийся у вас вариант (без изменения дизайна всех таблиц) — сохранить LIST_C.A в LIST_D, а затем создать FKey обратно в LIST_B .

Другой вариант — перепроектировать его таким образом, чтобы у вас были промежуточные таблицы, содержащие соответствующие ссылки между всеми таблицами, но, похоже, это нежелательно.