I would like to find all users not in a specific group, given the following database schema:
CREATE TABLE foobar_users (
user_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE foobar_groups (
group_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
groupname VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE foobar_users_groups (
user_id INT UNSIGNED NOT NULL,
group_id INT UNSIGNED NOT NULL,
PRIMARY KEY(user_id, group_id)
);
There are two common approaches to this problem, one is to use an outer-join and the other approach is to use a sub-select. Here is a left outer join example:
SELECT u.user_id, u.username FROM foobar_users u LEFT JOIN (foobar_users_groups ug, foobar_groups g) ON u.user_id = ug.user_id AND g.group_id = ug.group_id AND g.groupname = 'DMV' WHERE ug.user_id IS NULL
Alternatively, you can use a sub-select, e.g.,
SELECT u.user_id, u.username
FROM foobar_users u
WHERE u.user_id NOT IN (
SELECT ug.user_id
FROM foobar_groups g, foobar_users_groups ug
WHERE ug.group_id = g.group_id
AND g.groupname = 'DMV'
)
My personal preference, and arguably more efficient solution than the above two, is to use a sub-select with NOT EXISTS, as follows:
SELECT u.user_id, u.username
FROM foobar_users u
WHERE NOT EXISTS (
SELECT NULL
FROM foobar_groups g, foobar_users_groups ug
WHERE ug.group_id = g.group_id
AND ug.user_id = u.user_id
AND g.groupname = 'DMV'
)