外键是指跨多个表的主键?


91

我必须在数据库employees下有两个表,即employees_ce和employees_sn。

它们都有各自独特的主键列。

我还有另一个表称为扣除,该表的外键列我要引用employees_ce和employees_sn的主键。这可能吗?

例如

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

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

那有可能吗?

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

Answers:


98

假设我正确理解了您的情况,这就是我所说的正确方法:

从数据库的更高级描述开始!您有员工,而员工可以是“ ce”员工和“ sn”员工(无论是哪种员工)。用面向对象的术语讲,有一个“雇员”类,有两个子类,分别是“ ce employee”和“ sn employee”。

然后你这个更高层次的描述转换为三个表:employeesemployees_ceemployees_sn

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

由于所有员工都是员工(duh!),因此每个员工在employees表中都有一行。“ ce”员工在employees_ce表中也有一行,而“ sn”员工在employees_sn表中也有一行。employees_ce.id是的外键employees.id,照原样employees_sn.id

要提及任何类型的员工(ce或sn),请参阅employees表。也就是说,您遇到麻烦的外键应该参考该表!


17
您如何使ce和sn互斥?由于员工不能同时使用ce和sn,​​因此最好将其反映在数据库中。我现在有这个问题。
罗尔夫

我认为多个列键可以帮助解决我以前的评论中的问题...现在查找。
罗尔夫

12
您可以通过在基本表和派生表中存储类型来强制员工仅在表中的一个(以及正确的表)中。设置主键id,在(id,type)上的唯一键,在子表的外键在(id,type)上,然后在每个子表上设置CHECK约束以仅具有正确的类型。或者,如果您的数据库执行全局检查约束(并且不会造成巨大的速度损失),那么您当然可以进行“不存在”检查。
德罗伯特

查看此答案以获取完整的解释和实现细节。
PerformanceDBA

如何知道具有特定ID的员工是“ se”或“ sn”?
mhrsalehi

22

您可能可以添加两个外键约束(老实:我从未尝试过),但是它坚持认为父行存在于两个表中。

相反,您可能想为两个雇员子类型创建一个超类型,然后将外键指向那里。(当然,假设您有充分的理由将两种类型的员工分开)。

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

type员工表中的为cesn


我尝试添加多个外键,它们起作用了,但是在添加一条记录时,java derby告诉我,两个外键约束均已违反!

我只是在PostgreSQL上尝试过,它就可以在那工作。两个表中都有父记录吗?
derobert

父母记录你的意思是说,很爽?

当然,问题已经从“扣除”表转移到“雇员”表。您如何根据类型引用可能不同的实体?
gawpertron 2011年

1
@gawpertron:好吧,这种Empid在所有类型中都是唯一的。您可以使用“类型”字段来查看需要引用的子表。LEFT JOIN如果数量不足,或者只是全部。当不使用“员工”基表时,无法声明主键(因为它是引用tableA或tableB或…);现在可以了。分裂的智慧employees_ceemployees_sn假设,而这个假设指出。
德罗伯特

19

其实我自己做。我有一个名为“ Comments”的表,其中包含其他3个表中记录的注释。两种解决方案都无法真正处理您可能想要的所有事情。在您的情况下,您可以这样做:

解决方案1:

  1. 将一个tinyint字段添加到employees_ce和employees_sn,每个表中的默认值都不同(此字段表示“表标识符”,因此我们将其称为tid_ce和tid_sn)

  2. 使用表的PK和表ID字段在每个表上创建唯一索引。

  3. 在您的“扣除额”表中添加一个tinyint字段,以存储外键的后半部分(表ID)

  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.在'Deductions'表中创建第二个外键字段,在两个外键中允许Null值,并创建普通外键:

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

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

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

仅当列不为空时才检查完整性,因此您可以维护引用完整性。


6

我知道这是一个长期停滞不前的话题,但是如果有人在这里搜索,我将如何处理多表外键。使用这种技术,您没有任何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

技术上可行。您可能会在扣除和employees_sn中引用employees_ce。但是,为什么不合并employee_sn和employee_ce?我看不出您有两个桌子的原因。没有一对多的关系。并且(在本示例中不是)许多列。

如果您对一列进行两个引用,则雇员必须在两个表中都有一个条目。


1

是的,有可能。您将需要为第3个表定义2个FK。每个FK指向一个表的必填字段(即每个外部表1 FK)。


0

假设由于某种原因您必须为两个雇员类型拥有两个表,我将继续介绍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不支持数据库级别的约束这种关系,因此您必须确保您的应用正确管理约束(如果您有多个不同的应用/服务访问同一数据库,则这将变得更加麻烦)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.