2012-08-08 26 views
2

Previous Question我對於在n-m關係中具有複合主鍵有一些想法。我的情況非常相似,但有點不同。具有N-M關係的複合主鍵

[Person] 

    PERSON_ID: int, primary key 
    CLIENT_ID: int, primary key 
    Name: nvarchar(xx) 
    primary_key(PERSON_ID, CLIENT_ID); 

[Group] 

    GROUP_ID: int 
    CLIENT_ID: int 
    Name: nvarchar(xx) 
    primary_key(GROUP_ID, CLIENT_ID); 

現在,當我用mysql工作臺工具生成的關係表中它的作用是什麼它創建一個表:

選項1:

[PersonHasGroup] 

    PERSON_ID: int 
    CLIENT_ID: int 
    GROUP_ID: int 
    CLIENT1_ID: int 
primary_key(PERSON_ID, CLIENT_ID, GROUP_ID, CLIENT1_ID); 

在我的案例兩個client_id通常都會有相同的值,所以我編輯表格看起來像

選項2:

[PersonHasGroup] 

    PERSON_ID: int 
    CLIENT_ID: int 
    GROUP_ID: int 
primary_key(PERSON_ID, CLIENT_ID, GROUP_ID); 

那些是一個很好的做法?我的其他同事喜歡的是有點不同。他們使用:

方案3:

[PersonHasGroup] 
    PERSON_HAS_GROUP_ID: int, auto-increment 
    CLIENT_ID: int   
    PERSON_ID: int, foreign key 
    GROUP_ID: int, foreign key 
primary_key(PERSON_HAS_GROUP_ID, CLIENT_ID); 

哪些做法是合適的,當我的關係是多到多用一個例子解釋會有很多有益的:)

+2

您確實需要人的PK'CLIENT_ID'? – 2012-08-12 09:52:53

+0

你是什麼意思?是的,我很確定我需要它:)而這不是問題 – 2012-08-12 14:33:09

+0

所以你說兩個不同的人可以有相同的'PERSON_ID'? – 2012-08-12 22:03:03

回答

2

我寧願有一個很容易引用單個ID,併爲唯一的對,從來沒有使用過工作臺另一種獨特的關鍵,所以這裏是它首次在普通的SQL:

CREATE TABLE person_has_group (
    person_has_group_id SERIAL, 
    client_id BIGINT UNSIGNED NOT NULL REFERENCES clients (client_id), 
    person_id BIGINT UNSIGNED NOT NULL, 
    group_id BIGINT UNSIGNED NOT NULL, 
    FOREIGN KEY (client_id, person_id) REFERENCES persons (client_id, person_id), 
    FOREIGN KEY (client_id, group_id) REFERENCES groups (client_id, group_id), 
    UNIQUE KEY (client_id, person_id, group_id) 
); 

和proberly財產以後像這樣的「workbench」:

[PersonHasGroup] 
    PERSON_HAS_GROUP_ID: int, auto-increment 
    CLIENT_ID: int   
    PERSON_ID: int, foreign key 
    GROUP_ID: int, foreign key 
    primary_key(PERSON_HAS_GROUP_ID) 
    unique_key(CLIENT_ID, PERSON_ID, GROUP_ID); 
0

我認爲option 2會更好,因爲它還會在(PERSON_ID, CLIENT_ID, GROUP_ID)列上添加UNIQUE CONSTRAINT,以便不會將重複項插入到表中。

2

所提出的選項之間不應有任何爭議。有一個正確的答案,但答案取決於您的業務規則。

您的聲明「在我的情況下,兩個client_id通常具有相同的值」關注我。像正常情況一樣,通常在設計系統時不起作用。你需要用絕對數量來談論。

如果兩個關係的CLIENT_ID必須相同,則選項2(一個CLIENT_ID)是正確的設計。

但是,如果每種關係都可能基於不同的CLIENT_ID可能(可能很少但可能),那麼當然需要選項1和兩個唯一命名的CLIENT_ID列。 (我無法想象這種商業案例,但你的模型已經很奇怪,所以我不太確定)

沒有人可以幫助你確定哪些是正確的,除非你完全解釋你的業務需求,但你表明這是不可能的。

選項3不應該被認爲是一個選項 - 如果你要引入代理鍵,那麼它不應該是一個複合代理鍵。

我個人絕不會爲聯結表(可解析多對多關係的表)創建代理鍵,除非聯結表PK可以是另一個表中的外鍵。在這種情況下,我可能會出於性能原因創建代理鍵,但它不是一個簡單的選擇。如果創建代理鍵,則應聲明主鍵和備用鍵:一個使用自然組合鍵,另一個使用代理鍵。您想確保給定的組/人員對只輸入一次,並且您希望代理人也是唯一的。

所以這兩個選項1和2可以被修改爲包括代理鍵,如果你的特殊情況需要性能方面的原因:

方案1A

[PersonHasGroup] 
    PERSON_ID: int 
    PERSON_CLIENT_ID: int 
    GROUP_ID: int 
    GROUP_CLIENT_ID: int 
    PERSON_HAS_GROUP_ID: int 
primary_key(PERSON_ID, PERSON_CLIENT_ID, GROUP_ID, GROUP_CLIENT_ID); 
alternate_key(PERSON_HAS_GROUP_ID) 

選項2A

[PersonHasGroup] 
    PERSON_ID: int 
    CLIENT_ID: int 
    GROUP_ID: int 
    PERSON_HAS_GROUP_ID: int 
primary_key(PERSON_ID, CLIENT_ID, GROUP_ID); 
alternate_key(PERSON_HAS_GROUP_ID) 

當然,你可以扭轉哪個是主要的,哪個是備用的。

0

好問題。但讓我們先看看你的表。

考慮你的表的名稱,在每行似乎集團似乎代表被represnting一個和每一行。因此,從概念上來說,要識別不需要的人或組,Client_ID,因此您不需要它作爲主鍵的一部分。如果您的模型要求每個人都有唯一的Client_ID(除了您的Person_ID),只需將其設爲唯一字段,但不要將其包含在主鍵中。

這種情況與集團表有點混淆。問題是爲什麼一個組無法通過Group_ID獨自識別? (該CLIENT_ID場與一組到客戶端。但什麼是這種關係的性質是什麼?由客戶端創建的每個組?在這種情況下,你不需要有CLIENT_ID爲重點的一部分,你只需要把它作爲一個外鍵,它是一種會員關係嗎?在這種情況下,你需要一個由另一個表格表示的N到M關係)。

然後我們得到之間的關係。到M關係的N總是被轉換成由兩個表的+ N到M關係(如成員日期)的任何性質的PK的表。在這種情況下,您只需要有一個帶有兩個字段Person_IDGroup_ID的表,並且它們都是組合鍵的一部分。

您還必須小心命名.. PersonH​​asGroup代表什麼?這個人是否擁有這個團體?管理它?或者它只是一個會員。如果它是一個像「PersonGroup」這樣簡單的會員就足夠了。

確保你正確概念的實體看,否則你會陷入加起來主鍵字段和鏈接不完全滿足您的需求表的陷阱。保持封裝在其中的實體的屬性,而不要混合它們。問問自己「如何識別在現實世界中的實體?」 ...有你有你的答案的主鍵應該是什麼。喜歡的東西「在我的情況下,兩個CLIENT_ID通常會具有相同的值」是你看不到的概念正確和混合起來產生冗餘和不正確的關係的指示。

最後,我明白,有時候一個設計不當的數據庫交給你,你被要求引入新的聯繫和實體。我的建議是嘗試儘可能地糾正。從長遠來看,它會拯救你。

所以,在我看來,你的Previous Design是一個更好的設計相比,在一個這個問題。

1

如果我理解正確此,下面應該是真實的:

  • 你有幾臺服務器(DBS),每一個客戶端。

  • 每個DB都有自己的自動增量PersonIDGroupID

  • 您試圖簡單地(直接)導入所有到一個多租戶數據庫;因此PersonGroup表的主鍵中的ClientID

如果這些陳述不正確,請忽略其餘部分。

enter image description here

create table PersonGroup (
    PersonID integer 
    , GroupID integer 
    , ClientID integer 
); 

alter table PersonGroup add constraint pk_PersonGroup 
      primary key (PersonID, GroupID, ClientID); 

alter table PersonGroup add constraint fk1_PersonGroup 
      foreign key (PersonID, ClientID) references Person(PersonID, ClientID); 

alter table PersonGroup add constraint fk2_PersonGroup 
      foreign key (GroupID, ClientID) references Group(GroupID, ClientID);