基于逻辑 AND 而不是逻辑 OR 查找关联
Finding associations based on a logical AND instead of a logical OR
在我的数据模型中,一张照片可以关联很多标签。
所以我 photos
table 有两张照片。
id | file_name
----+----------------------
1 | DSCN0317.jpg
2 | DSCN0291.jpg
我的 tags
table 有两个标签
id | name
----+----------------
5 | Vacation
6 | Work
我有一个映射 table 将两者联系在一起。
photo_id | tag_id
----------+--------
1 | 5
2 | 5
2 | 6
所以在这个例子中,照片 1 有一个标签 (5),照片 2 有多个标签 (5, 6)
在我的应用程序中,我需要找到所有带有特定标签列表的照片。更重要的是,如果可能的话,我需要在一个查询中完成
(为什么它需要是单个查询的原因超出了这个问题的范围,并且与我的应用程序的具体实现有关)。
比如我想"find all photos that have both tags 5 and 6"
SELECT DISTINCT "photos".*
FROM "photos"
INNER JOIN "photo_tags"
ON "photo_tags"."photo_id" = "photos"."id"
WHERE "photo_tags"."tag_id" IN (5, 6)
;
但是这个查询是不正确的,因为它 returns 所有有标签 6 的照片 或 7. 我正在寻找有 6 [=38= 的照片]AND 7.
有什么方法可以转换上述查询来做到这一点吗?
谢谢!
在 tag_id:
上使用聚合和条件不同计数进行尝试
select p.*
from photos p
join (
select
photo_id
from tags
where
tag_id in (5, 6)
group by
photo_id
having
count(distinct tag_id) = 2
) t on p.id = t.photo_id;
或相关查询:
select p.*
from photos p
where exists (
select
1
from tags t
where
t.tag_id in (5, 6)
and t.photo_id = p.id
group by
id
having
count(distinct tag_id) = 2
);
您可以使用 EXISTS
查找同时具有 ID 5 和 ID 6 的照片:
SELECT "photos".*
FROM "photos"
WHERE EXISTS (
SELECT "photo_tags"."tag_id"
FROM "photo_tags"
WHERE "photo_tags"."photo_id" = "photos"."id"
AND "photo_tags"."tag_id" = 5)
AND EXISTS (
SELECT "photo_tags"."tag_id"
FROM "photo_tags"
WHERE "photo_tags"."photo_id" = "photos"."id"
AND "photo_tags"."tag_id" = 6)
在加入之前将标签聚合到数组中。然后检查数组是否包含所需的标签:
select distinct photos.*
from
photos
inner join (
select photo_id as id, array_agg(tag_id) as tags
from photo_tags
group by photo_id
) photo_tags using(id)
where array[5, 6] <@ tags
在我的数据模型中,一张照片可以关联很多标签。
所以我 photos
table 有两张照片。
id | file_name
----+----------------------
1 | DSCN0317.jpg
2 | DSCN0291.jpg
我的 tags
table 有两个标签
id | name
----+----------------
5 | Vacation
6 | Work
我有一个映射 table 将两者联系在一起。
photo_id | tag_id
----------+--------
1 | 5
2 | 5
2 | 6
所以在这个例子中,照片 1 有一个标签 (5),照片 2 有多个标签 (5, 6)
在我的应用程序中,我需要找到所有带有特定标签列表的照片。更重要的是,如果可能的话,我需要在一个查询中完成
(为什么它需要是单个查询的原因超出了这个问题的范围,并且与我的应用程序的具体实现有关)。
比如我想"find all photos that have both tags 5 and 6"
SELECT DISTINCT "photos".*
FROM "photos"
INNER JOIN "photo_tags"
ON "photo_tags"."photo_id" = "photos"."id"
WHERE "photo_tags"."tag_id" IN (5, 6)
;
但是这个查询是不正确的,因为它 returns 所有有标签 6 的照片 或 7. 我正在寻找有 6 [=38= 的照片]AND 7.
有什么方法可以转换上述查询来做到这一点吗?
谢谢!
在 tag_id:
上使用聚合和条件不同计数进行尝试select p.*
from photos p
join (
select
photo_id
from tags
where
tag_id in (5, 6)
group by
photo_id
having
count(distinct tag_id) = 2
) t on p.id = t.photo_id;
或相关查询:
select p.*
from photos p
where exists (
select
1
from tags t
where
t.tag_id in (5, 6)
and t.photo_id = p.id
group by
id
having
count(distinct tag_id) = 2
);
您可以使用 EXISTS
查找同时具有 ID 5 和 ID 6 的照片:
SELECT "photos".*
FROM "photos"
WHERE EXISTS (
SELECT "photo_tags"."tag_id"
FROM "photo_tags"
WHERE "photo_tags"."photo_id" = "photos"."id"
AND "photo_tags"."tag_id" = 5)
AND EXISTS (
SELECT "photo_tags"."tag_id"
FROM "photo_tags"
WHERE "photo_tags"."photo_id" = "photos"."id"
AND "photo_tags"."tag_id" = 6)
在加入之前将标签聚合到数组中。然后检查数组是否包含所需的标签:
select distinct photos.*
from
photos
inner join (
select photo_id as id, array_agg(tag_id) as tags
from photo_tags
group by photo_id
) photo_tags using(id)
where array[5, 6] <@ tags