9

在 Oracle 中取以下两张表:

Create Table A
( A int, B int, C int,
  Constraint pk_ab Primary Key(A, B),
  Unique (C)
);

Create Table B
( D int, E int, F int,
  Constraint fk_d Foreign Key (D) References A(A),
  Constraint fk_e Foreign Key (E) References A(B)
);

为什么这个说法不起作用?或者更具体地说,为什么它不能工作?我试图创建这种类型的关系的原因是,将来我想删除B.D,但保留关系FK_E

我收到错误:

ORA-02270: 此列列表没有匹配的唯一键或主键

4

3 回答 3

14

“为什么这个说法不起作用?或者更具体地说,为什么它不起作用?”

您已将 A 上的主键定义为两列 (A,B) 的组合。任何引用 PK_AB 的外键必须在数量上与这些列匹配。这是因为外键必须标识引用表中的单个行,该行拥有子表中的任何给定行。复合主键意味着 AA 列可以包含重复值,AB 列也可以;只有 (A,B) 的排列是唯一的。因此,引用外键需要两列。

Create Table B
( D int, E int, F int,
  Constraint fk_de Foreign Key (D,E) References A(A,B)
);

“由于表 B 引用了多个 PK”

错误的。B 引用单个主键,该主键恰好包含多个列,

“说,将来我想删除BD,但保留关系fk_e。”

那没有意义。可以这样想:D 不是 B 的属性,它是 B 通过其对表 A 的依赖而继承的属性。

避免这种情况的一种方法是使用代理(或合成)密钥。复合键通常是业务键,因此它们的列在业务上下文中是有意义的。有意义的列值的一个特征是它们可以更改,并且将此类更改级联到外键可能会很麻烦。

实现代理键如下所示:

Create Table A
( id int not null, A int, B int, C int,
  Constraint pk_a Primary Key(ID),
  constraint uk_ab Unique (A,B)
);

Create Table B
( a_id int, F int,
  Constraint fk_n_a Foreign Key (A_ID) References A(ID)
);

当然,您可以使用您发布的模式来执行此操作,因为您已经在 A(C) 上有一个单列约束。但是,我认为引用唯一约束而不是主键是不好的做法,即使它是允许的。我认为这部分是因为独特的约束通常会强制执行业务密钥,因此意味着意义,因此可能会发生变化,但主要是因为引用主键只是行业标准。

于 2013-01-27T05:59:45.820 回答
1

尝试为列AB创建表之前创建两个单独的索引B

CREATE INDEX a_idx ON A (A);
CREATE INDEX b_idx ON A (B);

但可能你需要一个复合 FK 在桌子上B

Create Table B
( D int, E int, F int,
  Constraint fk_d Foreign Key (D,E) References A(A,B)
);
于 2013-01-27T03:08:33.967 回答
0

外键总是引用另一个表的 PK。A 和 B 都不是 PK 的。你有多个 PK。

Constraint fk_d Foreign Key (D,E) References A(A,B)

此外,数据库无法验证部分空的多个外键,所以我认为检查约束也需要添加到表中。

alter table B add constraint check_nullness
    check ( ( D is not null and E is not null ) or
                ( D is null and E is null ) )
于 2013-01-27T03:08:45.793 回答