一对一关系约束

时间:2016-11-28 16:46:43

标签: database oracle database-design data-modeling

我实际上想要在Oracle的ERD中实现两个表之间的强制一对一关系。这两个表是州长和州。州长只能管理一个州,一个州必须只有一个州长。我想在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)
);

但这似乎不起作用。我找不到任何其他方式。请帮我解决一下这个。我会感激你的。请让我知道为什么没有建立一对一的关系。

3 个答案:

答案 0 :(得分:2)

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

  

"一个州必须有一个且只有一个统治者"

所以在STATE表上强制使用GID。

  

"治理者只能管理一个州"

因此,仅在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)
);
  

"我可以成功地将数据添加到gov表而不添加状态表中的任何行。"

强制父母必须有儿童关系非常困难。

  • SQL标准具有Assertions的概念,它可以强制执行这种业务规则,但Oracle(也没有任何其他DBMS供应商)已经实现了它们。
  • 引用STATE的GOV上的外键是正确的,因为循环依赖是致命的。
  • 让我们在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;
/

那么那就好了。只有一点皱纹:我们如何在任何一个表中插入行???? 我们不能插入GOV直到状态存在;我们不能插入STATE,直到调控器存在。

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

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

为什么这么难?通常,表之间的一对一关系是双方都必须的,这表明有缺陷的数据模型。

  1. 有时1:1指向一张桌子。这是不能令人满意的 我们有两个不同的实体,例如这里。
  2. 更可能是1:1 关系是错误的,它实际上是1:N甚至是M:N。考虑 一个国家可以有许多州长,一个当前,许多以前和 可选一个人。同样,政治家理论上也可以 在职业生涯中,不止一个州的州长。
  3. 因此,更真实的实现会将STATE_GOV作为STATE和GOV之间的交集表。维护这样一个表格要简单得多,这是一个好兆头。

答案 1 :(得分:1)

向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)
);

答案 2 :(得分:1)

从州表中删除FK。拥有它并使其独特意味着你不能在不知道州长的情况下进入一个州。使用每个FK上的唯一约束在State和Gov之间创建一个交集表:

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
);

任何州都不会出现多次,州长不会出现多次。在知道州长之前,没有循环引用,没有断言,插入状态记录没有问题。