首页 > 解决方案 > SQL查询多对多:查找给定集合中包含所有标签的所有项目

问题描述

我正在使用 SQLite。基本上,我在项目和标签之间有一个多对多的关系。我想找到每个项目,使其所有标签都包含在给定的集合中(由另一个查询找到)。因此,如果我有一个带有 tag1、tag2 和 tag3 的项目并且集合只有 tag1 和 tag2,我不应该得到那个项目。

我尝试了几种不同的方法,最新的方法是在选择的行中item_id,以便COUNT(item_id)在表Items_Tags中等于COUNT(item_id)条件tag IN (tag1, tag2)(例如)。当然,我只需要计算当前的外观,item_id我想不出一种方法来做到这一点:

SELECT i.item_id, i.item_name FROM Items i
    JOIN Items_Tags it
        ON i.item_id = it.item_id
    WHERE i.item_id IN (
        SELECT item_id FROM Items_Tags
            GROUP BY item_id
            HAVING COUNT(item_id) = (
                SELECT COUNT(item_id) FROM Items_Tags
                    WHERE item_id = current_item_id???
                    AND tag IN (tag1, tag2)
            )
    )

我确信我没有以最好的方式解决这个问题,因为我不习惯使用 SQL。任何帮助将不胜感激。

编辑:为了让自己更清楚,如果有三个项目:

给定的标签集是 tag1、tag2 和 tag3,我希望返回 item1 和 item2(因为它们的所有标签都包含在集合中),但不是 item3

标签: sqlsqlitemany-to-many

解决方案


加入表,按项目分组并在HAVING子句中使用条件聚合:

WITH tags_list(tag) AS (VALUES ('tag1'), ('tag2'))
SELECT i.item_id, i.item_name
FROM Items i JOIN Items_Tags it 
ON i.item_id = it.item_id
GROUP BY i.item_id, i.item_name
HAVING SUM(it.tag NOT IN tags_list) = 0

或与NOT EXISTS

WITH tags_list(tag) AS (VALUES ('tag1'), ('tag2'))
SELECT i.item_id, i.item_name
FROM Items i 
WHERE NOT EXISTS (
  SELECT 1 
  FROM Items_Tags it 
  WHERE it.item_id = i.item_id
    AND it.tag NOT IN tags_list
)

查看简化的演示


推荐阅读