仅使用在 `in` 子句中具有所有值的列连接查询
Join query with only columns that have all values in `in` clause
我正在为我的网站创建一个简单的过滤系统。我在场地和便利设施之间存在多对多关系。这是我的表格。
注意:所有 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' |
我正在尝试向 return 至少拥有所有通过 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');
这 return 是所有具有 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';
这return没什么。我正在尝试编写一个查询,其中如果 amenity_ids aaa
和 bbb
仅在会场 aaa
中传递 returned 因为它是唯一具有与两种便利设施的关系。此外,便利设施的数量在查询之间是动态的。
这是您要找的吗?
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
)
我想你正在寻找
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
)
);
这应该独立于有多少便利设施。
您可以在我指定的地方添加条件,以将查询限制为仅特定的设施或场所子集。
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
)
右:
- 这个的本质部分是只有 return venue_ids 用于外部 select.
- 您需要分组依据以方便使用 having。
- Having 是 where 子句的聚合形式。
- 有 2 确保 aaa AND bbb 都存在于 return 内部 select 中的场地 ID,而不是默认 或。
- count(1) - 对于聚合函数,您也可以使用列号而不是星号或列名。
证明代码有效:
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
您可以将 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'));
我正在为我的网站创建一个简单的过滤系统。我在场地和便利设施之间存在多对多关系。这是我的表格。
注意:所有 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' |
我正在尝试向 return 至少拥有所有通过 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');
这 return 是所有具有 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';
这return没什么。我正在尝试编写一个查询,其中如果 amenity_ids aaa
和 bbb
仅在会场 aaa
中传递 returned 因为它是唯一具有与两种便利设施的关系。此外,便利设施的数量在查询之间是动态的。
这是您要找的吗?
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
)
我想你正在寻找
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
)
);
这应该独立于有多少便利设施。
您可以在我指定的地方添加条件,以将查询限制为仅特定的设施或场所子集。
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
)
右:
- 这个的本质部分是只有 return venue_ids 用于外部 select.
- 您需要分组依据以方便使用 having。
- Having 是 where 子句的聚合形式。
- 有 2 确保 aaa AND bbb 都存在于 return 内部 select 中的场地 ID,而不是默认 或。
- count(1) - 对于聚合函数,您也可以使用列号而不是星号或列名。
证明代码有效:
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
您可以将 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'));