一对一关系约束

One-One relationship constraint

我实际上想在我的 Oracle ERD 中的两个表之间实现强制一对一关系。这两个表是 Governor 和 State。一个州长只能管理一个州,一个州必须有一个且只能有一个州长。我想在 Oracle 中实现它。我写了如下查询

create table gov
(gid number(3) ,name varchar2(100),
constraint gov_pk primary key (gid)
);

create table state
(
sid number(3) ,
name varchar2(100),
gid number(3),
constraint state_pk primary key (sid),
constraint gov_state_fk foreign key (gid) references gov(gid),
constraint state_uk unique(gid,name)
);

但这似乎不起作用。我找不到任何替代方法。请帮我解决一下这个。我会感谢你的。请告诉我为什么无法建立一对一关系。

向 STATE 添加唯一约束:

create table state
(
sid number(3) ,
name varchar2(100),
gid number(3),
constraint state_pk primary key (sid),
constraint gov_state_fk foreign key (gid) references gov(gid),
constraint state_uk unique(gid,name)
constraint gov_state_uk unique (gid)
);

您已经非常接近成功实现您的要求了。

" a state must have one and only one governer"

所以在 STATE table 上强制设置 GID。

"A governer can govern only one state "

所以只在 GID 上强制使用唯一密钥。

create table state
(
sid number(3) ,
name varchar2(100),
gid number(3) not null,
constraint state_pk primary key (sid),
constraint gov_state_fk foreign key (gid) references gov(gid),
constraint state_uk unique(gid)
);

"I can successfully add data to gov table with out adding any row in state table."

强制一个Parent必须有一个Child关系是相当困难的。

  • SQL 标准有断言的概念,它可以强制执行那种业务规则,但 Oracle(或任何其他 DBMS 供应商)尚未实现它们。
  • GOV 上引用 STATE 的外键是正确的,因为循环依赖是致命的。
  • 这让我们触发了 GOV。

这是一个触发器:

create or replace trigger enforce_gov_state 
    before insert or update on gov
    for each row
is
    l_sid state.sid%type;
begin
    select s.sid into l_sid
    from state s
    where s.gid = :new.gid;
exception
    when no_data_found then
        raise_application_error(-20000, 'Governor must have a state');
end;
/

那没关系。只是一个小问题:我们如何将行插入 table????? 在状态存在之前我们不能插入 GOV;在 governor 存在之前我们不能插入 STATE。

有一个解决方法:延迟 STATE 上的外键,这样它就不会在提交整个事务之前强制执行。这允许创建 STATE 记录,然后是 GOV 记录。当然,在创建GOV记录之前,我们需要知道STATE.GID的值。

此外,改变 GOV - STATE 关系也存在类似的障碍。除了它可以通过更新所有 GOV 属性(GID 除外)以适应新的 Governor 来解决。这有点粗略,但你去吧。


为什么 Oracle 让这件事变得如此困难?通常,table 之间的 one-to-one 关系在双方都是强制性的,这表明存在缺陷的数据模型。

  1. 有时 1:1 指向单个 table。这是不令人满意的时候 我们有两个不同的实体,例如此处。
  2. 更有可能 1:1 关系错了,居然是1:N甚至是M:N。考虑 一个州可以有很多州长,一位现任,多位前任和 可选地选出一个。同样,政治家在理论上可以是 在职业生涯中担任过多个州的州长。

因此,更真实的实施方式是 STATE_GOV 作为 STATE 和 GOV 之间的交集 table。维护这样的table就简单多了,这是个好兆头

从状态 table 中删除 FK。拥有它并使其独一无二意味着你不能在不认识州长的情况下进入一个州。在 State 和 Gov 之间创建一个交集 table,每个 FK 都有唯一约束:

create table StateGov(
  StateID   number( 3 ) not null references State( sid ),
  GovID     number( 3 ) not null references Gov( gid ),
  constraint UQ_StateGov_State unique StateID,
  constraint UQ_StateGov_Gov unique GovID
);

没有一个州可以出现超过一次,没有一个州长可以出现超过一次。没有循环引用,没有断言,在你知道州长之前插入状态记录没有问题。