【问题标题】:Foreign Key referring one field of two tables in oracle外键引用oracle中两个表的一个字段
【发布时间】:2013-05-06 11:09:44
【问题描述】:

我正在尝试通过引用不同的表来设置外键。

想象一下桌子:

Active_Card((主键)Num_id号码, num_card号码,is_active varchar2);

TMP_CARD((PK)num_card number, reg_date date);

DEFINITIVE_CARD((PK num_card number, name varchar, create_date date)

所以 num_card 是 Active_Card 的外键。我的问题是如何在 Active_card 中引用两个表(TMP_CARD 和 DEFINITIVE_CARD)。

最好的问候,

【问题讨论】:

  • 请告诉我们您正在寻找的语义。
  • 我正在尝试为外键设置语义
  • 如果 TMP_CARD 表不存在,我会: ALTER TABLE Active_Card ADD CONSTRAINT num_card_ibfk_1 FOREIGN KEY (num_card) REFERENCES DEFINITIVE_CARD (num_card);
  • 不是我要找的答案:我想知道您尝试建模的业务流程是什么样的。
  • 你不能。看来您需要 Active_Card 中的另一列作为第二个 num_card。所以 Active_Card 看起来像 Active_card((primary Key) Num_ID Number, definitive_num_card, number, tmp_num_card number, is_active).. 虽然这对我来说似乎很奇怪。您最好对数据进行规范化,这样您就有一个 Card_numbers 表,其中的字段为 (num_card, reg_date, name, create_date, Card_Type),知道 1 或 2 个字段将为空,具体取决于类型。

标签: database oracle plsql


【解决方案1】:

让我们解释一下为什么这不是一个好主意,然后从那里开始:

1st 假设 RDBMS 允许您这样做。

所以我们在Active_Card 中有与Definitive_CardTmp_Card 相关的FK。

现在假设我们有 123、456 的 definitive_card#s 和 123、789 的 tmp_card#s

外键强制参照完整性。所以 123 是可以的,因为它存在于两者中。 456 和 789 不会,因为它在两个表中都不存在。

但这不是我们想要的。您指出它需要在任一表中,而不是在评论中指出:*为了在 Active_Card 中有一个条目,它必须在 DEFINITIVE_CARD 或 TMP_CARD 中存在一个条目*

因此,由于您不希望两者都使用相同的 card_number,因此您实际上有 2-3 个选择:

  1. 将 Card_numbers 放在单独的表中,并通过关联表连接回 Active_card
  2. 在 Active_card 中添加第二个 card_number 列,根据填充的字段告诉您要转到哪个表以获取更多信息。
  3. 将 Definitive_Card 和 tmp_card 中的所有字段放在同一个表中

这些选项中的每一个都有自己的优缺点列表:但如果没有完全了解业务需求,我们无法说出最适合您的情况。

我们可以说您的尝试在 RDBMS 中根本行不通;但以上 3 个选项中的任何一个都将满足能够添加适当外键的要求

【讨论】:

    【解决方案2】:

    我认为提议的设计要求值得怀疑。我之前已经看到这种设计要求是由构建不良的对象模型进入构建不良的关系模型。

    尽管如此,如果要求 active_card.num_card 必须引用两个表,则物化视图可以实现设计要求。

    create table active_card( 
       num_id number primary key, 
       num_card number, 
       is_active varchar2(5) );
    create table tmp_card( 
       num_card number primary key, 
       reg_date date );
    create table definitive_card( 
       num_card number primary key, 
       name varchar(256), 
       create_date date );
    
    create or replace view card_v as
    select tc.num_card
      from tmp_card tc
     where exists ( select null 
                      from definitive_card dc 
                     where dc.num_card = tc.num_card );
    
    alter table active_card 
       add constraint active_card_num_card_fk 
       foreign key (num_card) 
       references card_v (num_card); -- won't work
    

    但是您不能针对视图创建外键...所以...创建一个物化视图:

    create materialized view log on tmp_card;
    create materialized view log on definitive_card;
    
    create materialized view card_mv
       build immediate 
       refresh fast 
       on commit
       as 
       select tc.num_card
         from tmp_card tc
        where exists ( select null 
                         from definitive_card dc 
                        where dc.num_card = tc.num_card )
    ;
    
    alter table active_card 
       add constraint active_card_num_card_fk 
       foreign key (num_card) 
       references card_mv (num_card); -- works
    
    insert into tmp_card values ( 123, sysdate );
    insert into tmp_card values ( 456, sysdate );
    insert into tmp_card values ( 789, sysdate );
    insert into definitive_card values ( 123, 'OneTwoThree', sysdate );
    insert into definitive_card values ( 789, 'SevenEightNine', sysdate );
    insert into definitive_card values ( 111, 'OneOneOne', sysdate );
    
    commit;
    

    现在...

    insert into active_card values ( 1, 123, 'true' ); -- succeeds
    insert into active_card values ( 1, 456, 'true' ); -- fails
    insert into active_card values ( 1, 111, 'true' ); -- fails
    
    delete from tmp_card where num_card = 789; -- succeeds
    commit;
    
    delete from tmp_card where num_card = 123; -- succeeds, but
    commit; --fails
    

    如果设计要求是 active_card.num_card 必须出现在两个表中,而不是两个表中,则需要调整物化视图定义。

    【讨论】:

      【解决方案3】:

      我怀疑您不想同时引用这两个表。您想引用一个另一个。

      为此,请使用单独的独占 FK。或者,使用继承。更多信息here.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-11
        • 2020-08-14
        • 2017-01-16
        • 1970-01-01
        • 1970-01-01
        • 2020-12-18
        • 2014-06-04
        相关资源
        最近更新 更多