Внешний ключ ссылается на первичные ключи в нескольких таблицах? - PullRequest
88 голосов
/ 21 марта 2009

У меня две таблицы, а именно employee_ce и employee_sn в базе данных сотрудников.

У них обоих есть соответствующие столбцы уникальных первичных ключей.

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

например

employees_ce
--------------
empid   name
khce1   prince

employees_sn
----------------
empid   name
khsn1   princess

так возможно ли это?

deductions
--------------
id      name
khce1   gold
khsn1   silver

Ответы [ 7 ]

92 голосов
/ 21 марта 2009

Предполагая, что я правильно понял ваш сценарий, это то, что я бы назвал правильный способ сделать это:

Начните с высокоуровневого описания вашей базы данных! У вас есть сотрудники, и сотрудники могут быть сотрудниками «ce» и «sn» (какими бы они ни были). В объектно-ориентированных терминах существует класс «employee» с двумя подклассами, называемыми «ce employee» и «sn employee».

Затем вы переводите это описание более высокого уровня в три таблицы: employees, employees_ce и employees_sn:

  • employees(id, name)
  • employees_ce(id, ce-specific stuff)
  • employees_sn(id, sn-specific stuff)

Поскольку все сотрудники являются сотрудниками (дух!), У каждого сотрудника будет строка в таблице employees. Сотрудники "ce" также имеют строку в таблице employees_ce, а сотрудники "sn" также имеют строку в таблице employees_sn. employees_ce.id - это внешний ключ для employees.id, так же как employees_sn.id.

Чтобы сослаться на сотрудника любого типа (ce или sn), обратитесь к таблице employees. То есть внешний ключ, с которым у вас возникли проблемы, должен ссылаться на эту таблицу!

22 голосов
/ 21 марта 2009

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

Вместо этого вы, вероятно, захотите создать супертип для двух ваших подтипов сотрудников, а затем вместо этого указать внешний ключ. (Разумеется, при условии, что у вас есть веская причина разделить два типа сотрудников).

                 employee       
employees_ce     ————————       employees_sn
————————————     type           ————————————
empid —————————> empid <——————— empid
name               /|\          name
                    |  
                    |  
      deductions    |  
      ——————————    |  
      empid ————————+  
      name

type в таблице сотрудников будет ce или sn.

18 голосов
/ 10 января 2012

На самом деле я делаю это сам. У меня есть таблица под названием «Комментарии», которая содержит комментарии для записей в 3 других таблицах. Ни одно из решений на самом деле не обрабатывает все, что вы, вероятно, хотите. В вашем случае вы бы сделали это:

Решение 1:

  1. Добавить поле tinyint в employee_ce и employee_sn, которое имеет значение по умолчанию, которое отличается в каждой таблице (Это поле представляет «идентификатор таблицы», поэтому мы будем называть их tid_ce & tid_sn)

  2. Создать уникальный индекс для каждой таблицы, используя PK таблицы и поле идентификатора таблицы.

  3. Добавить поле tinyint в таблицу «Отчисления» для хранения второй половины внешнего ключа (идентификатора таблицы)

  4. Создайте 2 внешних ключа в своей таблице «Отчислений» (Вы не можете навязать ссылочную целостность, потому что либо один ключ будет действительным, либо другой ... но никогда оба:

    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_ce] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_ce] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_ce]
    GO
    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_sn] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_sn] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_sn]
    GO
    
    employees_ce
    --------------
    empid    name     tid
    khce1   prince    1
    
    employees_sn
    ----------------
    empid    name     tid 
    khsn1   princess  2
    
    deductions
    ----------------------
    id      tid       name  
    khce1   1         gold
    khsn1   2         silver         
    ** id + tid creates a unique index **
    

Решение 2: Это решение позволяет поддерживать ссылочную целостность: 1. Создайте второе поле внешнего ключа в таблице «Отчисления», разрешите значения NULL в обоих внешних ключах и создайте нормальные внешние ключи:

    employees_ce
    --------------
    empid   name
    khce1   prince 

    employees_sn
    ----------------
    empid   name     
    khsn1   princess 

    deductions
    ----------------------
    idce    idsn      name  
    khce1   *NULL*    gold
    *NULL*  khsn1     silver         

Целостность проверяется только в том случае, если столбец не нулевой, поэтому вы можете поддерживать ссылочную целостность.

6 голосов
/ 28 апреля 2016

Я знаю, что это давно застойная тема, но в случае, если кто-то ищет здесь, я имею дело с внешними ключами нескольких таблиц. С помощью этой техники у вас нет никаких каскадных операций с применением DBA, поэтому убедитесь, что вы имеете дело с DELETE и тому подобным в вашем коде.

Table 1 Fruit
pk_fruitid, name
1, apple
2, pear

Table 2 Meat
Pk_meatid, name
1, beef
2, chicken

Table 3 Entity's
PK_entityid, anme
1, fruit
2, meat
3, desert

Table 4 Basket (Table using fk_s)
PK_basketid, fk_entityid, pseudo_entityrow
1, 2, 2 (Chicken - entity denotes meat table, pseudokey denotes row in indictaed table)
2, 1, 1 (Apple)
3, 1, 2 (pear)
4, 3, 1 (cheesecake)

Пример SO Op выглядел бы так:

deductions
--------------
type    id      name
1      khce1   gold
2      khsn1   silver

types
---------------------
1 employees_ce
2 employees_sn
1 голос
/ 21 марта 2009

Да, это возможно. Вам нужно будет определить 2 FK для 3-й таблицы. Каждый FK указывает на обязательное поле (я) одной таблицы (т.е. 1 FK на внешнюю таблицу).

1 голос
/ 21 марта 2009

Технически возможно. Вы бы, вероятно, ссылались на employee_ce в вычетах и ​​employee_sn. Но почему бы вам не объединить employee_sn и employee_ce? Я не вижу причин, почему у вас есть два стола. Отношения один ко многим. И (не в этом примере) много столбцов.

Если вы делаете две ссылки на один столбец, сотрудник должен иметь запись в обеих таблицах.

0 голосов
/ 11 мая 2011

Предполагая, что по каким-то причинам у вас должно быть две таблицы для двух типов сотрудников, я расширю ответ vmarquez:

Схема:

employees_ce (id, name)
employees_sn (id, name)
deductions (id, parentId, parentType, name)

Данные в вычетах:

deductions table
id      parentId      parentType      name
1       1             ce              gold
2       1             sn              silver
3       2             sn              wood
...

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

...