簡體   English   中英

如何使用Oracle聲明具有OR條件的外鍵?

[英]How to declare a foreign key with an OR condition using Oracle?

我有一個表(A),其主鍵是表(B)或表(C)的外鍵。

create table A (
  akey number, 
  txt varchar2(10)
);

create table B (
  bkey number, 
  txt varchar2(10)
);

create table C (
  ckey number, 
  txt varchar2(10)
);

我想要的是:

alter table A add constraint BorCkey foreign key (akey) references B(bkey)` or C(ckey);

這可能嗎?

外鍵約束是一個外表
這意味着在這種情況下你需要使用兩個ALTER TABLE語句來設置外鍵來引用這兩個表。 在那里沒有機會在關系中指定OR - A.akey的值必須同時存在於B.bkey C.ckey 例如,如果B.bkey的值為NULL,但C.ckey沒有 - 那么A.akey的值永遠不會為NULL。 外鍵在Oracle中是可延遲的,但所描述的行為是在同時啟用兩個外鍵時將遇到的行為 - 如果所有值都不滿足關系,則無法啟用約束。

您需要檢查您對如何簡化關系的需求,這樣就不需要兩個表來完成這項工作。

不,這種事情在Oracle中是不可能的。

您的選擇通常是

  • 在A中創建兩個不同的列(bkey和ckey),其中bkey引用B.bkey和ckey引用C.ckey並創建一個約束,確保在任何時間點只有一個非NULL。
  • 創建某種B&C具有外鍵的“組合B&C”實體,並使A中的外鍵成為該組合實體的關鍵。

如果需要一個約束,以確保兩列中只有一列為NULL,而對於任何行,其中一列為NOT NULL

create table one_key( 
  col1 number, 
  col2 number, 
  check( nvl2(col1,1,0) + nvl2(col2,1,0) = 1 ) 
)

聽起來你有某種形式的子類型/超類型關系。 一個典型的例子是'PERSON',它可以是'CUSTOMER'或'SUPPLIER'。

您可能在PERSON表中擁有PERSON_ID的唯一鍵以及PERSON_TYPE('CUST'或'SUPP')的屬性。 如果在PERSON_ID,PERSON_TYPE上創建主鍵,則可以在子類型表(SUPPLIER / CUSTOMER)中引用該主鍵。

然后在person_id上添加一個唯一約束,以確保person_id的任何值必須是客戶或供應商,而不是兩者,並檢查子類型表上的約束,以便表中只表示一種類型。

create table person
  (person_id     number,
   person_type   varchar2(4),
   name          varchar2(10),
    constraint person_pk primary key (person_id, person_type),
    constraint person_id_uk unique (person_id));

create table supplier
  (supplier_id   number,
   supplier_type varchar2(4),
   blah          varchar2(10),
  constraint supplier_pk primary key (supplier_id, supplier_type),
  constraint supp_pers_fk foreign key  (supplier_id, supplier_type)
    REFERENCES person (person_id, person_type)
  )
/
alter table supplier add constraint supp_type_ck check (supplier_type = 'SUPP');

它不漂亮但類型/子類型更多的是對象概念而不是關系概念。

我的解決方案受Justin的啟發:

CREATE OR REPLACE TRIGGER abc
  BEFORE INSERT OR UPDATE ON a
  FOR EACH ROW
  DECLARE
  v_testB NUMBER:= 0;
  v_testC NUMBER:= 0;
  BEGIN
    SELECT
      COUNT(bkey)
    INTO
      v_testB
    FROM
      b
    WHERE
      bkey = :new.aKey;
    SELECT
      COUNT(ckey)
    INTO
      v_testC
    FROM
      c
    WHERE
      ckey = :new.aKey;
    IF ((v_testB + v_testC) <> 1) THEN
      RAISE_APPLICATION_ERROR(-20002,'Foreign key to B or C missing.');
    END IF;
  END;
/
SHOW ERRORS TRIGGER abc

創建一個實體化視圖,用於聯合表B&C,並將FK約束指向視圖

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM