Each user
is on exactly one team
. A team has exactly one user in the team_lead
role. How can we normalize this in the database? Examples in pseudo-SQL:
Strategy 1:
table user:
id int pk
team_id int fk references team(id)
is_lead int //1 or 0
table team
id int pk
Problem: Multiple users on one team could be marked as the team lead
Strategy 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)
Problem: There is no guarantee the referenced team lead is actually a member of that team
Is there any way to normalize this in the database design, or do we have to use constraints or enforce on the front-end?
Best Answer
There's a (standard SQL) way of getting the guarantees you want, but I'm afraid mySQL 5.7 is not able to handle it. My example has been tested on PostgreSQL.
You can define your users table this way:
Then, have your teams have be defined in the following fashion:
By using a
composite foreign key constraint
you actually make sure that the user you are checking for, is actually a member of the team.After this second table has been defined, you can now add the foreign key constraint users.team_id -> teams.team_id:
Note that both tables are referrrig to each other. You have circular references.
Being this the case: the constraints must be checked at the end of a transaction, not just at the end of a statement. In the case of PostgreSQL, they need to be defined
DEFERRABLE
andINITIALLY DEFERRED
(this is what mySQL cannot handle). You need to enter data for the first team (tableteams
) and its team leader (tableusers
) all in one transaction, or, otherwise, there's no way to satisfy bothFOREIGN KEY
constraints:Let's assume these are 'user 1' and 'team 5':
Unfortunately, mySQL 5.7 documentation about foreign key constraints states:
MariaDB documentation about FKs doesn't have mentions about deferrability.