我正在为我的网站创建一个简单的过滤系统。场地和便利设施之间存在许多关系。这是我的桌子。
注意:所有ID均为uuid。让它们简明扼要
地点:
| id | name |
_________________________
| 'aaa' | 'first venue' |
| 'bbb' | 'second venue' |
| 'ccc' | 'third venue' |
设施:
| id | name |
___________________________
| 'aaa' | 'first amenity' |
| 'bbb' | 'second amenity' |
| 'ccc' | 'third amenity' |
amenity_venue:
| amenity_id | venue_id |
______________________________
| 'aaa' | 'aaa' |
| 'bbb' | 'aaa' |
| 'ccc' | 'aaa' |
| 'aaa' | 'bbb' |
| 'bbb' | 'ccc' |
我正在尝试编写查询以返回至少包含所有已通过amenity_ids传递的场所。例如,传递amenity_ids aaa
和bbb
。
输出,我正在寻找何时传入的设施ID为aaa
和bbb
。
| id | name |
_________________________
| 'aaa' | 'first venue' |
最初我尝试了此查询
select * from venues
INNER JOIN amenity_venue ON amenity_venue.venue_id = venues.id
where amenity_id in ('aaa', 'bbb');
这将返回所有amenity_id为aaa
或bbb
的场所
| id | name |
_________________________
| 'aaa' | 'first venue' |
| 'bbb' | 'second venue' |
| 'ccc' | 'third venue' |
所以我天真地尝试了
select * from venues
INNER JOIN amenity_venue ON amenity_venue.venue_id = venues.id
where amenity_id = 'aaa'
and amenity_id = 'bbb';
什么都不返回。我正在尝试编写一个查询,其中返回amenity_ids aaa
和bbb
仅在场所aaa
中传递,因为它是唯一与这两种便利设施都有关系的场所。而且,查询之间的便利设施数量是动态的。
答案 0 :(得分:0)
这是您要找的东西吗?
select * from venues
where exists (
select venue_id from amenity_venue
where venues.id = amenity_venue.venue_id and amenity_id in ('aaa', 'bbb')
group by venue_id
having count(*) = 2
)
答案 1 :(得分:0)
我认为您正在寻找
SELECT v.*
FROM venues v
WHERE v.name IN (/* list of venues names */)
AND NOT EXISTS (
SELECT 1
FROM amenities AS a
WHERE a.name IN (/* list of amenity names */)
AND NOT EXISTS (
SELECT 1
FROM amenity_venue AS av
WHERE av.venut_id = v.id
AND av.amenity_id = a.id
)
);
这应该独立于有多少便利设施而工作。
您可以在我指示的位置添加条件,以将查询限制为仅设施或场所的某些子集。
答案 2 :(得分:0)
select * from venues where id in(
select venue_id
from amenity_venue
where amenity_id in('aaa','bbb')
group by venue_id
having count(1) = 2
)
右:
证明代码有效:
https://rextester.com/TXQB38528
我做了一些小调整,并添加了此版本。
with amenities as (select 'aaa' as amenity_id UNION select 'bbb'),
ac as (select count(amenity_id) as tally from amenities)
select * from venues where id in(
select venue_id
from amenity_venue
where amenity_id in(select amenity_id from amenities)
group by venue_id
having count(1) = (select tally from ac)
);
这样一来,您就不会受到维护各种便利设施的束缚。 你可以在这里看到它。 https://rextester.com/TKRF28879
答案 3 :(得分:0)
您可以通过将ID汇总到一个数组中,然后将其与预期ID列表进行比较来实现此目的:
select v.*
from venues v
join amenity_venue av ON av.venue_id = v.id
group by v.id
having array_agg(av.amenity_id) @> array['aaa', 'bbb'];
以上假设venue.id
被声明为主键(由于group by
)。
如果您只想传递便利设施名称,则实际上不需要对查询中的ID进行硬编码:
select v.*
from venues v
join amenity_venue av ON av.venue_id = v.id
group by v.id
having array_agg(av.amenity_id) @> array(select id
from amenities
where name in ('first amenity', 'second amenity'));