问题描述
- 餐馆(餐厅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行)。
例如,假设
-
如
- 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个
- 然后输出
Identifier
中所示,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小提琴-。另外,仅供参考,请使用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)