Suppose I have a many-to-many relation between users and projects: one user may belong to several projects and one project may have multiple users. This relation is encoded in table user_projects:
create table user_projects
(
proj_id int references projs(id) not null,
user_id int references users(id) not null,
primary key (proj_id, user_id)
);
Here’s my problem: given a set of users (user1, user2, …), I want to select all projects for which the given set of users is a subset of all its users.
If, for example, I were insert the data below and then ask for all projects with users 1 and 2, then the query should return only project 1.
insert into user_projects values (1, 1);
insert into user_projects values (1, 2);
insert into user_projects values (1, 3);
insert into user_projects values (2, 1);
insert into user_projects values (2, 3);
(I’m using PostgreSQL, if the best solution happens to be non-standard.)
EDIT: For clarification, the set of users should be interpreted as a constraint on the list of projects to return. The set {u1, u2} means that the list of projects should include only those projects having at least users u1 and u2; the set {u1} means that all projects having at least user u1 should be returned, and as a limiting case, the empty set means that all projects should be returned.
You know that you have 2 users, you know that they will be unique (primary key)
so you know that if there are 2 records, for the same project then it’s one you want.
Your question indicated you have a GIVEN sent of users therefor you know what users and how many there are. the above SQL could be updated to accept parameters for these known and thus remains dynamic, not limited to just 2 users.
———–To handle situation when set of users is empty—–
So here’s what this does. It returns all projects and if there’s a user affiliated to that project it identifies them.
If you set contains users, the list of projects returned is filtered by that set ensuring that the entire set is in the project through the having clause.
If the set is empty, the LEFT join along with the userID is null statement will keep the projects with no users listed regardless of if the set is empty or not. The having clause will further reduce the set to the # of users you defined in the set, OR 0 indicating return all projects with no users assigned.
One additional edge case we didn’t discuss yet is what should happen if a project contains more users than what you defined in the set. Presently this project would be returned; but i’m not positive that’s what you wanted.
on a side note thanks for making me think. I don’t get to get into the code as much anymore; which is why I troll here from time to time to see if I can help!