Reputation: 4484
Three tables: users, roles and a pivot table (many to many) role_user.
user:
- id
- name
role:
- id
- name
role_user
- id
- user_id: foreign key link to user
- role_id: foreign key link to role
If I wanted to limit the amounts of maximum roles a user can have to only 1 for example, I could put the role_id foreign link on the user as a role_1 field instead of using a pivot table of many to many.
users:
- id
- name
- role_id_1
The same goes if I wanted only two roles per user.
users:
- id
- name
- role_id_1
- role_id_2
What if I wanted to limit the amount to 1, 2 or something else using a pivot table (Not using foreign role links on the user table) ? Is there an option for that in sql ?
Something like a composite unique index option including role_id and user_id in the pivot table, but instead of a constraint on the uniqueness, a custom constraint on the limit of the user_id number of appearances.
Upvotes: 1
Views: 3034
Reputation: 1269593
There is a way you can implement this in SQL without triggers. It is a bit complicated, but you could do it.
It starts by adding another table. Let me call it RoleNumbers
. This table would consist of one row for each possible role for a user. So, you set it up with 1, 2, or however many roles you want.
Then for the junction table:
create table UserRoles (
UserRoleId int not null auto_increment primary key,
UserId int not null references users(user_id),
RoleId int not null references roles(role_id),
RoleNumber int not null references RoleNumbers(Number),
unique (UserId, RoleId),
unique (UserId, RoleNumber)
);
This uses my naming conventions. I have no problem with having a synthetic key on a junction table.
When you insert a new record, you would have to assign a value to RoleNumber
that is not already being used. Hence, you get the limit. The most efficient way to do this is via triggers, but that is not strictly necessary. You could do an insert as:
insert into UserRoles(UserId, RoleId, RoleNumber)
select $UserId, $RoleId, coalesce(max(RoleNumber), 0) + 1
from UserRoles
where UserId = $UserId;
delete
would require a separate query for maintaining the numbering scheme.
Upvotes: 3