【问题标题】:One-One relationship constraint一对一关系约束
【发布时间】:2017-04-12 11:27:40
【问题描述】:

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

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

【问题讨论】:

  • 您可能希望状态表中的 gid 上有一个唯一键
  • 模型没有多大意义。您可能有一个“状态”表,并且可能是固定的(在大多数情况下,至少在一定时间内)。您还想要什么 - 一张州长表,其中包含出生日期和姓名等个人数据?如果一个人不再是州长怎么办,你会从表中删除他们吗?如果不是,那么这不是一对一的关系 - 一方面你可能有“零或一”。如果您确实需要始终保持一对一,为什么需要两张表?在 State 表中写入所有的Governor 属性。
  • 感谢@mathguy 的回复。它确实帮助消除了我的很多困惑。但是我仍然想问,如果我从表中删除一个管理者,为什么它不是一对一的关系?
  • 如果您在没有连任的情况下从表格中删除州长,那么这种关系实际上是一对一的 - 但在这种情况下,您不清楚为什么需要两个单独的表格.更有可能(更常见),您将有一个“政治家”或“潜在州长”表,其中一个人可能是一个州的州长或根本不是州长(此表中的“州”列,对于这个政治家,可能为 NULL)。当他们不再是州长时,您不会将“政治家”从桌面上删除。这是有道理的,但这种关系是一对(零或一)的。这是常见的安排。

标签: database oracle database-design data-modeling


【解决方案1】:

从状态表中删除 FK。拥有它并使其独一无二意味着你不能在不认识州长的情况下进入一个州。创建 State 和 Gov 之间的交集表,每个 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
);

任何州都不能出现多次,州长也不能出现多次。没有循环引用,没有断言,在你认识州长之前插入状态记录也没有问题。

【讨论】:

    【解决方案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 标准有断言的概念,可以强制执行这种业务规则,但 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 上,这样在提交整个事务之前不会强制执行。这允许创建状态记录,然后是 GOV 记录。当然,在创建 GOV 记录之前,我们需要知道 STATE.GID 的值。

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


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

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

    因此,更真实的实现将 STATE_GOV 作为 STATE 和 GOV 之间的交集表。维护这样一个表要简单得多,这是一个好兆头。

    【讨论】:

    • 这也行不通。我可以成功地将数据添加到 gov 表中,而无需在状态表中添加任何行。
    【解决方案3】:

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

    【讨论】:

    • name='A' - git=1 和 name='A' - git=2。不行 =(。我猜他应该在 name 字段上创建唯一索引,这将确保唯一的状态记录集,并因此与 gov 表建立一对一的关系
    • 这似乎不起作用。如果我应用一对一约束,那么如果没有另一个表中所需的数据,则不应插入任何表中的数据。假设我想插入一个新的治理者,那么还必须插入一个与他相关的状态,否则不应插入数据,但这只会使表中的治理者失效,这应该是不可能的。
    • 嗨,天行者你能解释一下吗?
    • @SalmanAli 如果每个州都需要一个州长,每个州长都需要一个州,为什么不只有一张桌子?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 2020-03-19
    • 2018-06-29
    • 2014-10-16
    • 2016-09-29
    • 1970-01-01
    • 2015-02-27
    相关资源
    最近更新 更多