我之前问了一个问题,但有点搞砸了,所以我在这里再次重新表述。
我有3个相关的表:
media
media_tags
(桥台)tags
这是我到目前为止的代码:
SELECT m.media_id, m.name, array_agg(distinct t.tag) filter (WHERE t.date_deleted IS NULL) AS tags
FROM media m
LEFT JOIN media_tags mt USING (media_id)
LEFT JOIN tags t USING (tag_id)
WHERE m.date_deleted IS NULL AND t.tag = ANY(array['dog','cat'])
GROUP BY m.media_id, m.name
这非常接近我想要的,但并不完全正确。 想象一下有这些媒体记录:
我上面的查询确实返回媒体 1、2 和 3,但显示的标签仅包含
dog
和 cat
。 我想要的是 tags
始终包含其所有标签(如果与数组中的任何值有任何匹配)。 因此,如果 ['dog','cat'] 在查询中,则媒体 1、2 和 3 应返回其各自的所有标签,但媒体 4 不应返回,因为没有匹配项。
我感觉我已经非常接近解决方案,但就是无法弄清楚。
执行此操作的 ANSI 标准方法(不使用 Postgres 数组)是首先查找所有匹配的标签,然后使用该结果来限制当前的查询。
WITH cte AS (
SELECT m.media_id
FROM media m
INNER JOIN media_tags mt ON mt.media_id = m.media_id
INNER JOIN tags t ON t.tag_id = mt.tag_id
WHERE t.tag IN ('dog', 'cat')
GROUP BY m.media_id
HAVING COUNT(DISTINCT t.tag) = 2
)
SELECT m.media_id, m.name, ARRAY_AGG(DISTINCT t.tag) FILTER (WHERE t.date_deleted IS NULL) AS tags
FROM media m
INNER JOIN media_tags mt ON mt.media_id = m.media_id
INNER JOIN tags t ON t.tag_id = mt.tag_id
WHERE m.media IN (SELECT media_id FROM cte)
GROUP BY m.media_id, m.name;