【问题标题】:Conditional Foreign Key implementation in oracleoracle中的条件外键实现
【发布时间】:2012-08-22 16:57:18
【问题描述】:

我有如下要求:

table1
------------------------
A    B     C    D   E    
------------------------
1    2     *    P    Q
1    2     A    Q    P
1    3     B    W    U
-----------------------

A B C 列是table1 上的primary key

table2
------------------------
A    B     C    
------------------------
1    2     1   
1    2     2   
1    2     A    
------------------------

A B C需要在table2上实现为复合外键 对于表 1 上的列 A B C,唯一的例外是,如果父表(表 1)中的列 C* 那么任何值都可以出现在column Acolumn B提供的子表(table2)的column C中 两张表都一样。

我们正在寻找一个触发器最少的实现。由于这个奇怪的要求,目前我们无法创建外键。

请提出任何替代方法并让我开心:)

【问题讨论】:

    标签: oracle plsql indexing oracle11g oracle11gr2


    【解决方案1】:

    无需任何新结构即可解决此问题。 只需在子表(table2)中引入一个新列(NEW_C) 并在外键约束中使用此列而不是“列 C”。 步骤如下:

    1>alter table2 add (new_c varchar2(1));

    2>update table2 set new_c= c;

    3>在 FK 中使用新引入的列 NEW_C 而不是 colum C

    alter table table2
      add constraint
      fk_ref_table1 FOREIGN KEY (A,B,**NEW_C**)    
      references table1 (A,B,C);
    

    4>在子表上创建一个简单的插入/更新触发器来维护新列NEW_C

    CREATE OR REPLACE maintain_new_c
     BEFORE
      INSERT OR UPDATE
      ON TABLE2 REFERENCING NEW AS NEW OLD AS OLD
     FOR EACH ROW
    DECLARE
    v_count pls_integer;
    BEGIN
     SELECT COUNT(1) 
       INTO v_count
       FROM table1 t1    
      WHERE t1.c='*'
        AND t1.a= :NEW.a 
        AND t1.b= :NEW.b;
    
      IF v_count=0 THEN
        new_c := :NEW.c ;
      ELSE
        new_c := '*';
      END IF;
    
    EXCEPTION
       WHEN OTHERS THEN
       RAISE_APPLICATION_ERROR..........
    END;
    

    替代方案是在子表上引入一个新的虚拟列(oracle 11g), 使用确定性 pl/sql 函数 派生这个虚拟列,然后创建外键约束 使用虚拟列。

    但我更喜欢基于触发器的方法作为父表上的任何 udate/delete 操作 会受到影响,因为每次都需要派生和检查虚拟列。

    【讨论】:

      【解决方案2】:

      我怀疑这是模型的问题。这两个表似乎代表两种不同类型的事物,这就是普通 FK 约束不起作用的原因。

      我认为您应该将两个表一分为二,例如:

      table1_noC
      ------------------------
      A    B     D   E    
      ------------------------
      1    2     P    Q
      
      table2_noC (with a FK to table1_noC)
      ------------------------
      A    B     C    
      ------------------------
      1    2     1   
      1    2     2   
      ------------------------
      
      table1_C
      ------------------------
      A    B     C    D   E    
      ------------------------
      1    2     A    Q    P
      1    3     B    W    U
      -----------------------
      
      table2_C (with a FK to table1_C)
      ------------------------
      A    B     C    
      ------------------------
      1    2     A    
      ------------------------
      

      然后,您可以使用结合了table1_noC + table1_C 的视图和结合了table2_noC + table2_C 的另一个视图重新创建原始设计。如有必要,您甚至可以向视图添加“替代”触发器,以将视图上的 DML 转换为基础表上必要的 DML。

      【讨论】:

      • :应用程序逻辑是基于这两个表的,为'column C'引入'*'是一个新的要求,所以不能合并包含4个表的新设计,一个不影响现有的解决方案功能是必需的:(
      • “我们想更改模型,但不想更改架构”...祝你好运:)
      猜你喜欢
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多