SQL |列出所有所有元组a,b,c,如果存在另一个具有相等b,c的元组

问题描述

我有三个表,其中粗体属性是主键

  • 餐馆(餐厅ID 名称,...)
resturant_ID,name,...
1,Macdonalds   
2,Hubert
3,Dorsia
...           ...
  • 标识符(餐厅ID 食品ID
restaurant_ID,food_ID,1
1,4
2,1
2,7
...            ...
  • Food( food_ID 名称,...)
food_ID    food_name
1          Chips
2          Burgers
3          Salmon
...        ...

我要使用postgres列出所有与至少一家其他餐厅共用完全相同的食物的餐厅(restaurant_id和名称-每个餐厅1行)。

例如,假设

    Identifier 中所示,
  • ID为“ 1”的餐厅仅 个关联food_id的1和4 Identifier
  • 中所示,
  • ID为“ 3”的餐厅仅关联关联food_id的4和1 Identifier
  • 中所示,
  • ID为“ 7”的餐厅仅关联了food_id的6 Identifier
  • 中所示,
  • ID为“ 9”的餐厅仅 个关联的food_id的6个
  • 然后输出
Restaurant_id      name
1                  name1
3                  name3
7                  ...
9                  ...

任何帮助将不胜感激!

谢谢

解决方法

使用汇总函数string_agg()获取每个餐厅的食物的完整列表:

with cte as (
  select restaurant_ID,string_agg(food_ID::varchar(10),',' order by food_ID) foods
  from identifier
  group by restaurant_ID
)
select r.* 
from Restaurants r inner join cte c
on c.restaurant_ID = r.restaurant_ID
where exists (select 1 from cte where restaurant_ID <> c.restaurant_ID and foods = c.foods)

但是我宁愿根据匹配的食物对餐馆进行分组:

with cte as (
  select restaurant_ID,' order by food_ID) foods
  from identifier
  group by restaurant_ID
)
select string_agg(r.name,') restaurants
from Restaurants r inner join cte c
on c.restaurant_ID = r.restaurant_ID
group by foods
having count(*) > 1

请参见demo

,

这是一种获得具有完全相同食品的独特的调理剂的方法。这使用了array_agg()和array_to_string()函数

Canada
     {'NAME': 'John','NICKNAME': 'Big John','COUNTRY': 'Canada','CITY': 'Toronto'}
     {'NAME': 'David','NICKNAME': 'Small Jogn','CITY': 'Toronto'}
England
     {'NAME': 'Alan','NICKNAME': 'The Bull','COUNTRY': 'England','CITY': 'London'}
     {'NAME': 'Ethan','NICKNAME': 'The Hawk','CITY': 'London'}
Russia
     {'NAME': 'Ivan','NICKNAME': 'The Russian','COUNTRY': 'Russia','CITY': 'Moscow'}
     {'NAME': 'Boris','NICKNAME': 'The Bear','CITY': 'Moscow'}

编辑:这是dB小提琴-enter image description here。另外,仅供参考,请使用listagg函数-https://dbfiddle.uk/?rdbms=postgres_12&fiddle=e2de05edfbe036cc0d81c64d60f0b599

解决Oracle中的同一问题

更新:下面的查询解决了问题的更新输出格式。

 With cte as
(select T.restaurant_id,array_to_string(array_agg(food_id),') as food_list
from
(select *
  from Identifier t1
  order by restaurant_id,food_id) T
  group by T.restaurant_id)

select 
   concat(r1.name,r2.name) as resturant_names,t1.restaurant_id as restaurant_id1,r1.name as restaurant_1,t2.restaurant_id as restaurant_id2,r2.name as restaurant_2,t1.food_list as common_food_ids
from cte t1
join cte t2
on t1.restaurant_id < t2.restaurant_id
and t1.food_list = t2.food_list
left join Restaurants r1
on t1.restaurant_id = r1.restaurant_id
left join Restaurants r2
on t2.restaurant_id = r2.restaurant_id;
,

据我所知,您希望所有餐厅的食物清单与餐厅1相同。

如果是这样,那就是关系划分问题。这是一种使用联接和聚合的方法:

select r.name
from identifier i1
inner join identifier i2 on i2.food_id = i1.food_id
inner join restaurant r on r.restaurant_id = i2.restaurant_id
where i1.restaurant_id = 1
group by r.restaurant_id
having count(*) = (select count(*) from identifier i3 where i3.restaurant_id = 1)