2016-11-28 150 views
0

我實際上想要在Oracle的ERD中實現兩個表之間的強制一對一關係。這兩張表格是州長和州長。一個州長只能管理一個州,一個州必須有一個且只有一個省長。我想在Oracle中實現它。我寫了如下查詢一對一關係約束

create table gov 
(gid number(3) ,name varchar2(100), 
constraint gov_pk primary key (gid) 
); 

create table state 
(
sid number(3) , 
name varchar2(100), 
gid number(3), 
constraint state_pk primary key (sid), 
constraint gov_state_fk foreign key (gid) references gov(gid), 
constraint state_uk unique(gid,name) 
); 

但這似乎並不奏效。我找不到任何替代方法。請幫我解決一下這個。我會感謝你。請讓我知道爲什麼沒有建立一對一的關係。

+0

你可能想要一個唯一的關鍵只是在狀態表中的gid –

+0

該模型沒有多大意義。你可能有一個「狀態」表,這可能是固定的(在大多數情況下,至少在一定的時間內)。你還想要什麼 - 一張總督表,上面有個人資料,如出生日期和姓名?如果一個人不再是總督,你會從桌面上刪除它們嗎?如果不是,那麼它不是一對一的關係 - 一方面你可能有「零或一個」。如果你真的需要永遠保持一對一,爲什麼你需要兩張桌子?在State表中寫下所有的Governor屬性。 – mathguy

+0

謝謝@mathguy您的回覆。它確實幫助我消除了很多混亂。但是,我仍然想問,如果我從表中刪除一個管理員,爲什麼它不是一對一的關係? –

回答

2

你很接近成功實現您的要求。

「的狀態必須有且只有一個調速器」

所以讓GID必須在狀態表。

「A調速器可以支配只有一個狀態」

所以強制執行只是GID的唯一關鍵。

create table state 
(
sid number(3) , 
name varchar2(100), 
gid number(3) not null, 
constraint state_pk primary key (sid), 
constraint gov_state_fk foreign key (gid) references gov(gid), 
constraint state_uk unique(gid) 
); 

「我可以成功地與數據出狀態表中添加任何行添加到GOV表」。

強制家長必須有一個孩子的關係是非常困難的。

  • SQL標準具有斷言的概念,它可以強制執行這種業務規則,但是Oracle(或任何其他DBMS供應商)已經實現了它們。
  • GOV引用STATE的外鍵是正確的,因爲循環依賴是致命的。
  • 讓我們在GOV上觸發一個觸發器。

這裏有這樣一個觸發器:

create or replace trigger enforce_gov_state 
    before insert or update on gov 
    for each row 
is 
    l_sid state.sid%type; 
begin 
    select s.sid into l_sid 
    from state s 
    where s.gid = :new.gid; 
exception 
    when no_data_found then 
     raise_application_error(-20000, 'Governor must have a state'); 
end; 
/

所以沒關係呢。只有一點點皺紋:我們如何將行插入到任何一個表中?直到狀態存在,我們才能插入GOV;我們不能在州長存在之前插入STATE。

有一個解決方法:在STATE上推遲外鍵,以便在提交整個事務之前不會強制執行。這允許創建STATE記錄,然後是GOV記錄。當然,在我們創建GOV記錄之前,我們需要知道STATE.GID的值。

此外,還有類似的障礙,以改變GOV - STATE關係。除了它可以通過更新所有GOV屬​​性(GID除外)來適應新的總督來解決。這是一種粗略,但你去。


爲什麼這麼難?通常,表格之間的一對一關係是雙方都必須指出的一個有缺陷的數據模型。

  1. 有時1:1指向一張表。當 我們有兩個不同的實體,例如這裏,這是不令人滿意的。
  2. 更可能是1:1 關係錯誤,它實際上是1:N甚至M:N。考慮 一個國家可以有許多州長,一個當前,許多以前和任選一個選民。同樣,一個政治家在理論上可以是職業生涯中不止一個州的州長。

所以一個更真實的實現將STATE_GOV作爲STATE和GOV之間的交集表。維護這樣一張桌子就簡單多了,這是一個好兆頭。

+0

這也行不通。將數據添加到gov表而不添加狀態表中的任何行。 –

+0

謝謝@APC提供這樣的解釋性答案。我真的很喜歡它幫了我很多。非常感謝你。 –

1

添加唯一約束來STATE:

create table state 
(
sid number(3) , 
name varchar2(100), 
gid number(3), 
constraint state_pk primary key (sid), 
constraint gov_state_fk foreign key (gid) references gov(gid), 
constraint state_uk unique(gid,name) 
constraint gov_state_uk unique (gid) 
); 
+0

* name ='A' - git = 1 and name ='A' - git = 2 *。不工作=(。我猜他應該在名稱字段上創建唯一的索引,這將確保唯一的狀態記錄集並與政府表 – SkyWalker

+0

結果一對一的關係這似乎並不奏效如果我應用one-one約束,那麼數據在任何表中不應該插入沒有所需的數據在另一個表中。假設我想插入一個新的管理者,那麼還必須插入一個與他有關的狀態,否則不應該插入數據,但這只是惰性表中的管理員這應該是不可能的 –

+0

嗨,, SkyWalker你能解釋一下嗎? –

1

從狀態表中刪除FK。擁有它並使之獨一無二意味着如果不知道州長就不能進入州。在每個FK唯一約束創建國家和州長之間的交點表:

create table StateGov(
    StateID number(3) not null references State(sid), 
    GovID  number(3) not null references Gov(gid), 
    constraint UQ_StateGov_State unique StateID, 
    constraint UQ_StateGov_Gov unique GovID 
); 

任何國家都不能出現多次,沒有州長會出現不止一次。沒有循環引用,沒有斷言,在知道州長之前插入狀態記錄沒有問題。