I have a table, two columns, user and group. It’s a many-to-many relationship, so we might have…
group | user
1 | 1
1 | 2
1 | 3
2 | 1
2 | 3
3 | 1
3 | 4
4 | 2
4 | 3
… and so on.
I need to get a list of users in all the groups which contain a particular a user ID. So for the above, if I gave it user ID 3, it would first get all the groups for that (in this case, 1, 2, and 4), and then return all the users for those groups (in this case, 1, 2, and 3). Right now, this is accomplished through two nested selects:
SELECT * FROM other_table
WHERE user_id IN (
SELECT user_id FROM table WHERE group_id IN (
SELECT group_id FROM table WHERE user_id = 3
)
)
This is proving horribly inefficient. Is there something obvious I’m missing here?
Even if I run the query on its own, it runs very inefficiently:
SELECT user_id FROM table WHERE group_id IN (
SELECT group_id FROM table WHERE user_id = 3
)
Edit: Here’s the CREATE TABLE for the table.
CREATE TABLE `user_groups` (
`user_id` bigint(12) unsigned NOT NULL,
`group_id` bigint(12) unsigned NOT NULL,
PRIMARY KEY (`user_id`,`group_id`),
KEY `user_id` (`user_id`),
KEY `group_id` (`group_id`),
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Edit: And the explain of what happens with the query in the answer below:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | SIMPLE | t1 | ref | PRIMARY,user_id,group_id | PRIMARY | 8 | const | 839 | Using index
1 | SIMPLE | t2 | ref | PRIMARY,user_id,group_id | group_id | 8 | t1.group_id | 2331 |
1 | SIMPLE | users | eq_ref | PRIMARY | PRIMARY | 8 | t2.user_id | 1 |
Just use a self-join: