ChatGPT解决这个技术问题 Extra ChatGPT

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

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

它们都有各自唯一的主键列。

我有另一个名为 deductions 的表,我想引用employees_ce 和employees_sn 的主键的外键列。这可能吗?

例如

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

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

那么这可能吗?

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

T
Thomas Padron-McCarthy

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

从您的数据库的更高级别描述开始!您有员工,员工可以是“ce”员工和“sn”员工(无论是什么)。在面向对象的术语中,有一个类“employee”,有两个子类,分别称为“ce employee”和“sn employee”。

然后将此更高级别的描述转换为三个表:employeesemployees_ceemployees_sn

员工(身份证,姓名)

employees_ce(id, ce 特定的东西)

employees_sn(id, sn-specific stuff)

由于所有员工都是员工(呃!),因此每个员工都会在 employees 表中占一行。 “ce”员工在 employees_ce 表中也有一行,“sn”员工在 employees_sn 表中也有一行。 employees_ce.idemployees.id 的外键,就像 employees_sn.id 一样。

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


如何让 ce 和 sn 互斥?由于员工不能同时是 ce 和 sn,因此最好将其反映在数据库中。我现在遇到这个问题。
我认为多个列键可以帮助解决我之前评论中的问题......现在查找。
您可以通过将类型存储在基表和派生表中来强制员工仅在一个表中(和正确的表)。使主键 id,唯一键在 (id,type) 上,子表的外键在 (id, type) 上,并在每个子表上放置一个 CHECK 约束,使其只有正确的类型。或者,如果您的数据库执行全局检查约束(并且没有巨大的速度损失),您当然可以只进行 NOT EXISTS 检查。
查看 this Answer 了解完整说明和实施细节。
如何知道具有特定 id 的员工是 'se' 还是 'sn' ?
d
derobert

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

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

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

雇员表中的 type 将是 cesn


我尝试添加多个外键,它们起作用了,但是在添加记录时,java derby 告诉我两个外键约束都被违反了!
我刚刚在 PostgreSQL 上试过,它在那里工作。您在两个表中都有父记录吗?
父记录你的意思是说,empid?
当然,问题已经从“扣除”表转移到了“雇员”表。您将如何根据类型引用可能不同的实体?
@gawpertron:嗯,empid 在所有类型中都是独一无二的。您可以使用“类型”字段来查看需要引用的子表。或者只是LEFT JOIN全部,如果数量足够少的话。当不使用 'employee' 基表时,无法声明主键(因为它正在引用 tableA 或 tableB 或……);现在可以了。假设拆分 employees_ceemployees_sn 是明智的,并注意到该假设。
L
LittleC

其实这是我自己做的。我有一个名为“评论”的表,其中包含其他 3 个表中记录的评论。这两种解决方案实际上都无法处理您可能想要的所有内容。在你的情况下,你会这样做:

解决方案1:

在employees_ce 和employees_sn 中添加一个tinyint 字段,该字段的默认值在每个表中都不同(该字段表示“表标识符”,因此我们将它们称为tid_ce & tid_sn)使用表的PK 在每个表上创建唯一索引和表 id 字段。在您的“扣除”表中添加一个 tinyint 字段以存储外键的后半部分(表 ID)在您的“扣除”表中创建 2 个外键(您不能强制引用完整性,因为任何一个键都是有效的或其他...但绝不会同时使用:ALTER TABLE [dbo].[Deductions] WITH NOCHECK ADD CONSTRAINT [FK_Deductions_employees_ce] FOREIGN KEY([id], [fk_tid]) REFERENCES [dbo].[employees_ce] ([empid], [tid]) 不用于复制 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])参考 [dbo].[employees_sn] ([empid], [tid]) 不用于复制 GO ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_sn] GO employees_ce ------------- - empid 名称 tid khce1 王子 1 雇员_sn ---------------- empid 名称 tid khsn1 公主 2 扣除 -------------------------------- --- id tid 名称 khce1 1 金 khsn 1 2 silver ** id + tid 创建唯一索引 **

解决方案 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         

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


C
Chax

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

S
Sascha

技术上可行。您可能会在扣减和employees_sn 中引用employees_ce。但是为什么不合并employees_sn 和employees_ce?我看不出你有两张桌子的理由。没有一对多的关系。并且(不在此示例中)许多列。

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


v
vmarquez

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


r
r00fus

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