2017-04-11 57 views
0

我有以下表格:如何在沒有所有列時添加引用複合主鍵的外鍵,但可以通過另一個外鍵獲取它們?

create table AAA 
(
    AAA_ID NUMBER 
); 

alter table AAA 
    add constraint AAA_PK 
    primary key (AAA_ID); 

create table BBB 
(
    BBB_ID NUMBER, 
    AAA_ID NUMBER 
); 

alter table BBB 
    add constraint BBB_PK 
    primary key (BBB_ID, AAA_ID); --IMPORTANT 

alter table BBB 
    add constraint BBB_FK_01 
    foreign key (AAA_ID) 
    references AAA (AAA_ID); 

create table CCC 
(
    CCC_ID NUMBER, 
    AAA_ID NUMBER 
); 

alter table CCC 
    add constraint CCC_PK 
    primary key (CCC_ID); --IMPORTANT 

alter table CCC 
    add constraint CCC_FK_01 
    foreign key (AAA_ID) 
    references AAA (AAA_ID); 

create table CCC_BBB 
(
    CCC_ID NUMBER, 
    CCC_BBB_ID NUMBER, 
    BBB_ID NUMBER 
); 

alter table CCC_BBB 
    add constraint CCC_BBB_PK 
    primary key (CCC_ID, CCC_BBB_ID); 

alter table CCC_BBB 
    add constraint CCC_BBB_FK_01 
    foreign key (CCC_ID) 
    references CCC (CCC_ID); 

我想在CCC_BBB引用BBB添加一個外鍵約束。 BBB_ID直接存在於CCC_BBB,但沒有AAA_ID。然而,AAA_ID存在於CCC中,其由CCC_BBB_FK_01引用。有沒有可能在SQL中表達這個約束?

我更喜歡符合標準的解決方案,但也歡迎Oracle特定的解決方案。

編輯。我被要求澄清什麼是現實世界問題,所以這是我的嘗試(我不想在這裏討論真正的問題域):

AAA是一個過程。 BBB是一個過程步驟。幾個進程具有相似名稱的步驟,但含義不同,所以該表具有組合鍵。 CCC是一個流程實例。他們的ID是唯一的,所以表沒有組合PK。 CCC_BBB是在特定實例中採取的步驟列表。

我需要確保流程實例的步驟列表僅包含那些流程允許的步驟。

+2

我不相信你所描述的是可能的。 –

+0

似乎你的理論範例並不完全合理。 – jarlh

+0

在創建完所有表後,您可以使用一種方法觸發所有alter命令 –

回答

1

你的問題似乎源於組合鍵只有一半應用。

讓我們先從技術非複合鍵開始。爲了增強可讀性,我稍微改名了表名和列名。主鍵是粗體。

  • A(A_ID,COL1,COL2,......)
  • AB(AB_ID,A_ID,COL1,COL2,......)
  • AC(AC_ID,A_ID, COL1,COL2,......)
  • ABC(ABC_ID,AC_ID,AB_ID,COL1,COL2,......)

^h我們有你描述的情況:AC和AB是A的孩子,ABC是AB和AC的孩子,但DBMS不能保證BC包含B和C,它們都屬於同一個A.這是一個衆所周知的方法,在純粹基於ID的數據庫設計中存在已知的缺點;它無法保證表的層次結構的一致性。

現在同樣的複合主鍵(這是很常見的自然鍵,但隨着技術的ID工作,太):

  • A(A_ID,COL1,COL2,......)
  • AB(A_ID,B_ID,COL1,COL2,......)
  • AC(A_ID,C_ID,COL1,COL2,......)
  • ABC(A_ID,B_ID, C_ID,col1,col2,...)

這裏一致性是有保證的,因爲完整的父鍵總是主鍵的一部分。

你在做什麼是一個混合。您正在將複合鍵應用到最後一個表,但是在所有父表中您沒有,因此爲時已晚。您已經使用了非複合ID概念,並且存在一致性缺陷。

  • A(A_ID,COL1,COL2,......)
  • AB(AB_ID,A_ID,COL1,COL2,......)
  • AC(AC_ID,A_ID, COL1,COL2,......)
  • ABC(AC_ID,ACSUB_ID,AB_ID,COL1,COL2,......)
+0

所以簡短的答案是否定的,除非我添加AAA_ID/A_ID到我的CCC/AC表PK,即使它是多餘的? – Alexey

+0

答案是:如果您使用非複合ID,則不具備您希望獲得的一致性保證。如果你使用複合ID,那麼你可以得到它,但是你自己必須保持一致:給BBB和CCC組合鍵並且編寫CCC_BBB的兩個鍵。這沒什麼多餘的。 –

+0

當然你也可以混淆。爲CCC_BBB提供AAA_ID冗餘,並在BBB(BBB_ID,AAA_ID)上添加一個(多餘的)唯一約束,然後您可以在CCC_BBB中爲外鍵使用該約束。我只是不會推薦這個。 –

0

ÿ OU可以使用物化視圖來連接兩個表,然後添加外鍵,這一點:

CREATE MATERIALIZED VIEW LOG ON CCC_BBB 
    WITH SEQUENCE, ROWID(CCC_ID,CCC_BBB_ID,BBB_ID) 
    INCLUDING NEW VALUES; 

CREATE MATERIALIZED VIEW CCC_BBB_MV 
    BUILD IMMEDIATE 
    REFRESH FAST ON COMMIT 
    AS SELECT CCC_ID, 
      CCC_BBB_ID, 
      BBB_ID, 
      AAA_ID 
     FROM CCC_BBB b 
      INNER JOIN 
      CCC c 
      ON (b.CCC_ID = c.CCC_ID); 

ALTER TABLE CCC_BBB_MV ADD CONSTRAINT ccc_bbb_mv__fk 
    FOREIGN KEY (AAA_ID, BBB_ID) REFERENCES BBB (AAA_ID, BBB_ID); 

上面的代碼是未經測試,但要說明的解決方案)的

雖然它可能工作,這是一個黑客,並且您將使用較少的存儲空間來將AAA_ID添加到您的CCC_BBB表中。

相關問題