Cada um user
está exatamente em um team
. Uma equipe tem exatamente um usuário na team_lead
função. Como podemos normalizar isso no banco de dados? Exemplos em pseudo-SQL:
Estratégia 1:
table user:
id int pk
team_id int fk references team(id)
is_lead int //1 or 0
table team
id int pk
Problema: vários usuários em uma equipe podem ser marcados como o líder da equipe
Estratégia 2:
table user:
id int pk
team_id int fk references team(id)
table team
id int pk
team_lead_id int fk references user(id)
Problema: não há garantia de que o líder de equipe referenciado seja realmente um membro dessa equipe
Existe alguma maneira de normalizar isso no design do banco de dados ou temos que usar restrições ou impor no front-end?
Existe uma maneira (SQL padrão) de obter as garantias que você deseja, mas receio que o mySQL 5.7 não seja capaz de lidar com isso. Meu exemplo foi testado no PostgreSQL.
Você pode definir sua tabela de usuários desta maneira:
Em seguida, tenha suas equipes definidas da seguinte maneira:
Ao usar um
composite foreign key constraint
, você realmente garante que o usuário que está verificando é realmente um membro da equipe.Depois que esta segunda tabela foi definida, agora você pode adicionar a restrição de chave estrangeira users.team_id -> teams.team_id:
Observe que ambas as tabelas se referem uma à outra. Você tem referências circulares.
Sendo assim: as restrições devem ser verificadas ao final de uma transação, não apenas ao final de um extrato. No caso do PostgreSQL, eles precisam ser definidos
DEFERRABLE
eINITIALLY DEFERRED
(é com isso que o mySQL não consegue lidar). Você precisa inserir dados para a primeira equipe (tabelateams
) e seu líder de equipe (tabelausers
) em uma única transação ou, caso contrário, não há como satisfazer as duasFOREIGN KEY
restrições:Vamos supor que sejam 'usuário 1' e 'equipe 5':
Infelizmente, a documentação do mySQL 5.7 sobre restrições de chaves estrangeiras afirma:
A documentação do MariaDB sobre FKs não menciona a possibilidade de adiamento.
Não é nada complicado. Você já deve ter uma tabela de referência cruzada/interseção para os relacionamentos mm Usuário-Equipe:
A restrição FK é típica dessas tabelas. Ele garante que o mesmo jogador não pode ser listado mais de uma vez para o mesmo time.
A restrição Unique garante que o mesmo jogador não pode ser listado mais de uma vez em todas as equipes.
Você pensaria que a restrição Unique torna o PK supérfluo. Na verdade, não.
Embora possa ser colocado em uma tabela separada, o líder da equipe é um atributo da equipe, então vou mostrá-lo como parte da tabela Teams:
Ao referenciar o FK à tabela de cruzamento, garantimos que o líder da equipa é um utilizador já definido como jogador da equipa.
Assim, você garante que cada usuário está em exatamente um time e um time tem exatamente um usuário na função team_lead e esse usuário é aquele que está jogando no time.