Как мне лучше спроектировать базу данных, где у меня есть одна таблица игроков (с первичным ключом player_id ), которую я хочу объединить в группы по две, чтобы база данных могла применять ограничение, которое состоит из каждой команды из ровно двух игроков, и каждый игрок в не более одной команды?
Я могу придумать два решения, но оба они меня не очень устраивают.
Одна возможность состоит в том, чтобы иметь два столбца player1_id и player2_id , которые являются уникальными внешними ключами, указывающими на столбец player_id в плеере Таблица. Требуется дополнительная проверка, чтобы ни один игрок не являлся одновременно игроком 1 одной команды и игроком 2 второй команды.
Другая возможность, которая приходит мне в голову, - это соединить игровой стол и командный стол с таблицей членства в команде, которая имеет уникальный внешний ключ к столбцу player_id в стол игрока и второй внешний ключ, указывающий на первичный ключ таблицы команды. Здесь нужно добавить проверку, что в каждой команде ровно два участника.
Есть ли лучший дизайн, который упрощает проверку ограничений?
Если это имеет значение: я использую базу данных PostgreSQL 8.4, и я предпочитаю ее мощную систему правил триггерам, где это возможно.
РЕДАКТИРОВАТЬ: решение на основе ответа Алексея Кузнецова
Мне это пока не кажется идеальным, но мне это нравится намного лучше, чем было раньше. Я изменил решение Алекса, так как я не хочу иметь внешний ключ от игроков к командам, так как на этапе подачи заявки игроки могут зарегистрироваться.
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 игрока. Чтобы убедиться, что в каждой команде есть участники, я мог бы добавить внешний ключ в таблицу команд, который указывает на любое из двух членств. Но, как и Эрвин, я не фанат отложенной проверки ограничений. Есть идеи, как улучшить это? Или есть совершенно другой, лучший подход?
PS: метод работает также для команд с n> 2 игроками. Нужно просто заменить OtherNumberInTeam на NextNumberInTeam со значением (т.е. ограничением) NumberInTeam + 1 mod n.