为什么复合外键需要单独的唯一约束?


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)中的一个已被保证是唯一的时,我不明白为什么有必要这样做?从我的角度来看,新约束将是多余的。

Answers:


11

据我所知,这是DBMS的局限性。而且不仅在添加列时,而且在重新排列列时也是如此。如果我们对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

似乎没有被要求,或者它没有被认为具有足够高的优先级来实施。

您始终可以在相应的渠道中请求实施该功能。如果DBMS是开源的(例如Postgres),甚至可以自己实现。


我不确定是否会这么简单。部分索引或NULL值呢?等等。如果您对NULL满意,则NULL可能仍然可以正常工作NULL != NULL。无论如何.. :)
Joishi Bodio

@JoishiBodio我不认为Null是个问题。可以定义UNIQUE约束,也可以将其设为空列。默认值为如果任何列的值为NULL,则传递约束并接受行。
ypercubeᵀᴹ

但是在第二个方面,如果a1,a2,... aN不可为空,而b1,b2,bM可能会出现问题。但是肯定可以为不可为空的列实现该功能。效率问题可能令人担忧。
ypercubeᵀᴹ

我熟悉UNIQUE INDEX列的位置NULLABLE。这就是为什么我提到它。:)但我同意-在没有NULL(也没有部分索引)的情况下,这可能非常简单。
Joishi Bodio

5

通常,外键(不仅仅是外键)必须指向另一个表中某种形式的唯一键。如果不这样做,就不会有关系数据的完整性。

这是在抱怨,因为尽管您在(id)上具有唯一键..您在(id,num)上没有唯一键。因此,就数据库而言,对(id,num)是不能保证是唯一的。我们,作为人类,可以发现它是唯一的,但是我敢肯定,他们将不得不添加很多其他代码,以使Postgres变得足够聪明,从而看到“哦,.. id应该是唯一的” ,因此id,num也应该是唯一的”。

如果他们要做的就是在两列上创建另一个唯一索引来解决问题,那么他们将添加该代码,我将感到非常惊讶。

需要明确的是,他们将不得不添加的代码不只是这种简单的情况……它必须处理所有情况,甚至那些外键在4+列上的情况,等等。我敢肯定逻辑将非常复杂。

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.