oracle中的条件外键实现

时间:2012-08-28 07:51:50

标签: oracle plsql indexing oracle11g oracle11gr2

我有如下所述的要求:

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

A B Cprimary key

上的table1
table2
------------------------
A    B     C    
------------------------
1    2     1   
1    2     2   
1    2     A    
------------------------

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

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

请建议任何替代方法,让我的一天:)

2 个答案:

答案 0 :(得分: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。

答案 1 :(得分:2)

无需任何新结构即可解决此问题。  只是在子表中引入new_column(NEW_C)(table2) 并在外键约束中使用此列而不是“列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函数 派生这个虚拟coulmn,然后创建外键约束 使用虚拟列。

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