mysql - SQL:在双重多对多关系中查找交集

标签 mysql sql mariadb relational-division

以下是我的架构和数据的简化版本:

用户:

id | name
 1 | Peter
 2 | Max
 3 | Susan

餐厅:

id | name
 1 | Mario
 2 | Ali
 3 | Alfonzo
 4 | BurgerQueen

菜肴:

id | name
 1 | Burger
 2 | Pizza
 3 | Salad

用户菜肴:

user_id | dish_id
      1 | 1
      2 | 1
      2 | 2
      3 | 2
      3 | 3

餐厅菜肴:

restaurant_id | dish_id
            1 | 2
            1 | 3
            2 | 1
            2 | 3
            3 | 1
            3 | 2
            3 | 3
            4 | 1

所以我有三个实体:用户餐馆菜肴。 以及两个多对多关系。

  • users-dishes 关系定义了用户可以吃什么。
  • 关系餐厅-菜肴定义了餐厅可以提供的服务。

作为输入,我有一个用户 ID 列表。 我现在需要的是找到列表中的所有用户都可以吃到他们喜欢吃的所有餐厅。

考虑以下查询:

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

这显示了每个用户可以访问的所有餐厅。

user  | restaurants
Peter | Alfonzo,Ali,BurgerQueen
Max   | Alfonzo,Ali,BurgerQueen,Mario
Susan | Alfonzo,Ali,Mario

所以我需要的是集合的交集。 您已经可以看到所有三个用户都可以转到 Alfonzo 和 Ali。 但是彼得不能去找马里奥。苏珊不能去 BurgerQueen。

结果(对于用户 ID 1、2、3)应该是:

id | name
 2 | Ali
 3 | Alfonzo

对于 ID 1、2 应该是

id | restaurant
 2 | Ali
 3 | Alfonzo
 4 | BurgerQueen

对于 ID 2、3 应该是

id | restaurant
 1 | Mario
 2 | Ali
 3 | Alfonzo

您可以使用以下 SQL 脚本创建架构和示例数据:

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);

我还准备了一个SQL-fiddle on db-fiddle.com .

我还应该提到我需要一个与 MySQL 5.7 和 MariaDB 10.1 兼容的解决方案

最佳答案

经典relational division . “最简单”的方法之一是:

select *
from restaurants r
where not exists (
  select *
  from users u
  where not exists (
    select *
    from users_dishes ud
    join restaurants_dishes rd on ud.dish_id = rd.dish_id
    where ud.user_id = u.id
    and rd.restaurant_id = r.id
  )
  and u.id in (1, 2, 3)
)

Demo here .换句话说,如果有一个用户在给定的餐厅没有菜,那么给定的餐厅就不能容纳所有用户。因此,我们想要获取没有用户的餐厅,该餐厅没有菜。

关于mysql - SQL:在双重多对多关系中查找交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55148813/

相关文章:

mysql - MySql Inner Join 的问题 > 未包含在聚合函数或 GROUP BY 子句中

mysql - 如果两个参数都不为空

mysql - MariaDB 从站错误 - 字符串对于 MASTER_HOST 来说太长

sql - 关于如何替换MariaDB语句中的UNION子句的思考

php - 在 PHP 中连接到数据库

php - 使用左外连接从多个表中获取数据 - PDO

PHP 里面的 javascript 函数?

Mysql语法错误

sql - 没有时间戳的检索

unicode - 从 utf8mb4_unicode_520_ci 升级 MariaDB 排序规则