1

我有如下要求:

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

A B Cprimary keytable1

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

A B C需要实现为A B C表 1 上的列的表 2 上的复合外键,唯一的例外是,如果C父表(表 1)中的列是* 任何值可以出现在column C提供的子表(表 2)中,column A并且column B 两者都相同表。

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

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

4

2 回答 2

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的另一个视图重新创建原始设计。如有必要,您甚至可以向视图添加“替代”触发器,以将视图上的 DML 转换为基础表上必要的 DML。table2_noCtable2_C

于 2012-08-28T08:23:57.553 回答
2

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

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

2> update table2 set new_c= c;

3>使用新引入的列 NEW_C 而不是colum CFK

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 操作都会受到影响,因为每次都需要派生和检查虚拟列。

于 2012-08-29T04:08:18.857 回答