【发布时间】:2010-11-10 18:21:11
【问题描述】:
我如何最好地设计一个数据库,其中我有一个球员表(主键 player_id),我想将其配对成两个团队,以便数据库可以强制执行每个团队的约束由正好两个玩家组成,每个玩家最多一个队?
我可以想到两种解决方案,但我都不太满意。
一种可能性是有两列 player1_id 和 player2_id 是 唯一 指向 player_id 的外键玩家表中的列。需要进行额外检查,以确保没有球员同时是一队的 player1 和另一队的 player2。
我想到的另一种可能性是将玩家表和团队表连接到一个团队成员表,该表具有 player_id 列的唯一外键在 player 表中,第二个外键指向 team 表的主键。这里必须添加一个检查,每个团队只有两个成员。
是否有更好的设计来简化约束检查?
如果重要的话:我使用的数据库是 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。
【问题讨论】:
-
有postgres物化视图吗?
标签: sql database-design postgresql