Following is a simplified version of my schema and data:
users:
id | name
1 | Peter
2 | Max
3 | Susan
restaurants:
id | name
1 | Mario
2 | Ali
3 | Alfonzo
4 | BurgerQueen
dishes:
id | name
1 | Burger
2 | Pizza
3 | Salad
users_dishes:
user_id | dish_id
1 | 1
2 | 1
2 | 2
3 | 2
3 | 3
restaurants_dishes:
restaurant_id | dish_id
1 | 2
1 | 3
2 | 1
2 | 3
3 | 1
3 | 2
3 | 3
4 | 1
So I have three entities: users, restaurants and dishes. And two many-to-many relations.
- The relation users-dishes defines what a user can eat.
- The relation restaurants-dishes defines what a restaurant can serve.
As input I have a list of user IDs. What I need now, is to find all restaurants where all users from the list can eat what they like.
Consider the following query:
select u.name as user, group_concat(distinct r.name) as dishes
from users u
join users_dishes ud on ud.user_id = u.id
join restaurants_dishes rd on rd.dish_id = ud.dish_id
join restaurants r on r.id = rd.restaurant_id
group by u.id
This shows all restaurants, that each user can visit.
user | restaurants
Peter | Alfonzo,Ali,BurgerQueen
Max | Alfonzo,Ali,BurgerQueen,Mario
Susan | Alfonzo,Ali,Mario
So what I need is the intersection of the sets. You can already see that all three users can go to Alfonzo and Ali. But Peter can not go to Mariao. And Susan can not go to BurgerQueen.
The result (for the user IDs 1,2,3) should be:
id | name
2 | Ali
3 | Alfonzo
For IDs 1, 2 it should be
id | restaurant
2 | Ali
3 | Alfonzo
4 | BurgerQueen
For IDs 2, 3 it should be
id | restaurant
1 | Mario
2 | Ali
3 | Alfonzo
You can create schema and sample data with the following SQL script:
CREATE TABLE users (id INT AUTO_INCREMENT,name varchar(100),PRIMARY KEY (id));
INSERT INTO users(name) VALUES ('Peter'),('Max'),('Susan');
CREATE TABLE restaurants (id INT AUTO_INCREMENT,name varchar(100),PRIMARY KEY (id));
INSERT INTO restaurants(name) VALUES ('Mario'),('Ali'),('Alfonzo'),('BurgerQueen');
CREATE TABLE dishes (id INT AUTO_INCREMENT,name varchar(100),PRIMARY KEY (id));
INSERT INTO dishes(name) VALUES ('Burger'),('Pizza'),('Salad');
CREATE TABLE users_dishes (user_id INT,dish_id INT,PRIMARY KEY (user_id, dish_id),INDEX (dish_id, user_id));
INSERT INTO users_dishes(user_id, dish_id) VALUES (1,1),(2,1),(2,2),(3,2),(3,3);
CREATE TABLE restaurants_dishes (restaurant_id INT,dish_id INT,PRIMARY KEY (restaurant_id, dish_id),INDEX (dish_id, restaurant_id));
INSERT INTO restaurants_dishes(restaurant_id, dish_id) VALUES (1,2),(1,3),(2,1),(2,3),(3,1),(3,2),(3,3),(4,1);
I have also prepared an SQL-fiddle on db-fiddle.com.
I should also mention that I need a solution compatible to MySQL 5.7 and MariaDB 10.1