2009-07-14 22 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这样的系统的建立,明确的目的是纯粹处理这些类型的约束执行问题,即纯粹以声明方式处理,即不涉及任何触发器的麻烦或涉及任何其他形式的编程。你可能会感兴趣。