2009-07-14 67 views
-1

我如何最好地設計一個數據庫,其中我有一個球員表(主鍵player_id),我想將它們配對爲兩個球隊,以便數據庫可以強制約束每個球員球隊組成正好兩位球員和每位球員是最多一個球隊?用於約束強制配對的數據庫設計

我可以想到兩個解決方案,但我都不太滿意。

一種可能性是有兩列player1_idplayer2_id是指着球員表player_id獨特外鍵。需要進行額外的檢查,以便沒有球員同時參加一個球隊的球員1和另一個球隊的球員2。

是在我腦海中的另一種可能是給玩家表和球隊表具有唯一外鍵在播放表中的player_id塔和第二外鍵一個團隊成員表連接指向團隊表的主鍵。這裏必須補充一點,每個團隊都有兩個成員。

是否有更好的設計可以簡化對約束的檢查?

如果很重要:我使用的數據庫是PostgreSQL 8.4,我更喜歡它的功能強大的rule system觸發器儘可能。

編輯:基於AlexKuznetsov

的回答解決方案。它並不感到完美的我,但我喜歡它比我以前好多了。我修改了Alex的解決方案,因爲我不想讓隊員擁有外鍵,因爲有一個應用程序階段,玩家可以註冊。

create table TeamMemberships(
    player_id int not null unique references Players(player_id), 
    team_id int not null references Teams(team_id), 
    NumberInTeam int not null check(NumberInTeam in (0,1)), 
    OtherNumberInTeam int not null, -- check(OtherNumberInTeam in (0,1)) is implied 
    check(NumberInTeam + OtherNumberInTeam = 1) 
    foreign key (team_id, OtherNumberInTeam) references TeamMemberships(team_id, NumberInTeam), 
    primary key (team_id, NumberInTeam) 
); 

此定義確保團隊成員資格成對(並且將成對插入)。現在球員最多隻能有一個球隊,球隊可以有0個或2個球員。爲了確保每個團隊都有成員,我可以在團隊表中添加一個指向任何兩個成員的外鍵。但是像Erwin一樣,我不是延遲約束檢查的粉絲。任何想法如何改善這方面呢?還是有一個完全不同的,更好的方法?

PS:這些方法也適用於n> 2的球員。只需用NextNumberInTeam替換OtherNumberInTeam和值(即約束)NumberInTeam + 1 mod n即可。

+0

有postgres物化視圖嗎? – FerranB 2009-07-14 20:31:20

回答

1

我不知道這是否可以在Postgress工作,但這裏是一個SQL Server解決方案:

CREATE TABLE dbo.Teams(TeamID INT NOT NULL PRIMARY KEY); 
GO 
CREATE TABLE dbo.Players(PlayerID INT NOT NULL PRIMARY KEY, 
    TeamID INT NOT NULL FOREIGN KEY REFERENCES dbo.Teams(TeamID), 
    NumberInTeam INT NOT NULL CHECK(NumberInTeam IN (1,2)), 
    TeamMateID INT NOT NULL, 
    TeamMatesNumberInTeam INT NOT NULL, 
-- if NumberInTeam=1 then TeamMatesNumberInTeam must be 2 
-- and vise versa 
    CHECK(NumberInTeam+TeamMatesNumberInTeam = 3), 
    UNIQUE(TeamID, NumberInTeam), 
    UNIQUE(PlayerID, TeamID, NumberInTeam), 
    FOREIGN KEY(TeamMateID, TeamID, TeamMatesNumberInTeam) 
    REFERENCES dbo.Players(PlayerID, TeamID, NumberInTeam) 
); 

INSERT INTO dbo.Teams(TeamID) SELECT 1 UNION ALL SELECT 2; 
GO 

- 你只能在完成對插入的球員

INSERT INTO dbo.Players(PlayerID, TeamID, NumberInTeam, TeamMateID, TeamMatesNumberInTeam) 
SELECT 1,1,1,2,2 UNION ALL 
SELECT 2,1,2,1,1; 

你可以嘗試插入單個玩家,或者從一個團隊中刪除一個玩家,或者爲每個團隊插入兩個以上的玩家 - 由於一套完整的約束,所有這些都會失敗。

注意:SQL Server中的做法是顯式命名所有約束。我沒有將我的約束命名,以防與Postgres不兼容。

0

這聽起來像是在用戶界面中比在數據庫中更容易實施的東西。

向球隊添加球員時,不允許添加超過2名球員,並且只允許添加不在球隊中的球員。

0

如果可能有必要變更爲有三名成員的團隊,第一種解決方案是有限的。

我喜歡teamMemebrs表的想法,但爲了執行您的約束,您將無法一次只插入一條記錄。你所有的插入將必須是兩個一組。此外,當你在A隊的球員Aia,並且你希望他被轉移到B隊時,你會做些什麼複雜的事情。現在你必須找到某個人轉移到A隊,然後將他和他的隊友加入隊伍B.

創建和填充團隊可能會更好,但如果他們有兩個成員並且每個成員只在一個團隊中,那麼他們只能活動?至少可以一次執行一個更改。 SP可以將A隊從A隊移到B隊,並讓A隊處於非活動狀態,直到找到另一個人加入隊。

0

在我看來,使用player1-id player2_id設計,在單個插入到您的團隊表後,您可以檢查所有約束。

在團隊+團隊成員設計中,除了必須設置的觸發/規則之外,您還會遇到延遲約束檢查的醜陋之處。附帶說一句:像SIRA_PRISE這樣的系統的建立,明確的目的是純粹處理這些類型的約束執行問題,即純粹以聲明方式處理,即不涉及任何觸發器的麻煩或涉及任何其他形式的編程。你可能會感興趣。