2016-11-28 147 views
0

我实际上想要在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) 
); 

但这似乎并不奏效。我找不到任何替代方法。请帮我解决一下这个。我会感谢你。请让我知道为什么没有建立一对一的关系。

+0

你可能想要一个唯一的关键只是在状态表中的gid –

+0

该模型没有多大意义。你可能有一个“状态”表,这可能是固定的(在大多数情况下,至少在一定的时间内)。你还想要什么 - 一张总督表,上面有个人资料,如出生日期和姓名?如果一个人不再是总督,你会从桌面上删除它们吗?如果不是,那么它不是一对一的关系 - 一方面你可能有“零或一个”。如果你真的需要永远保持一对一,为什么你需要两张桌子?在State表中写下所有的Governor属性。 – mathguy

+0

谢谢@mathguy您的回复。它确实帮助我消除了很多混乱。但是,我仍然想问,如果我从表中删除一个管理员,为什么它不是一对一的关系? –

回答

2

你很接近成功实现您的要求。

“的状态必须有且只有一个调速器”

所以让GID必须在状态表。

“A调速器可以支配只有一个状态”

所以强制执行只是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标准具有断言的概念,它可以强制执行这种业务规则,但是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; 
/

所以没关系呢。只有一点点皱纹:我们如何将行插入到任何一个表中?直到状态存在,我们才能插入GOV;我们不能在州长存在之前插入STATE。

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

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


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

  1. 有时1:1指向一张表。当 我们有两个不同的实体,例如这里,这是不令人满意的。
  2. 更可能是1:1 关系错误,它实际上是1:N甚至M:N。考虑 一个国家可以有许多州长,一个当前,许多以前和任选一个选民。同样,一个政治家在理论上可以是职业生涯中不止一个州的州长。

所以一个更真实的实现将STATE_GOV作为STATE和GOV之间的交集表。维护这样一张桌子就简单多了,这是一个好兆头。

+0

这也行不通。将数据添加到gov表而不添加状态表中的任何行。 –

+0

谢谢@APC提供这样的解释性答案。我真的很喜欢它帮了我很多。非常感谢你。 –

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

* name ='A' - git = 1 and name ='A' - git = 2 *。不工作=(。我猜他应该在名称字段上创建唯一的索引,这将确保唯一的状态记录集并与政府表 – SkyWalker

+0

结果一对一的关系这似乎并不奏效如果我应用one-one约束,那么数据在任何表中不应该插入没有所需的数据在另一个表中。假设我想插入一个新的管理者,那么还必须插入一个与他有关的状态,否则不应该插入数据,但这只是惰性表中的管理员这应该是不可能的 –

+0

嗨,, SkyWalker你能解释一下吗? –

1

从状态表中删除FK。拥有它并使之独一无二意味着如果不知道州长就不能进入州。在每个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 
); 

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