首页 > 解决方案 > 使用 IN 子句连接表,其中必须匹配所有值

问题描述

我在这里看到了一些类似的答案,但我无法让它们工作。我基本上有两张表,一张有内容,一张桥接标签。我想获取具有关联标签的内容。如果我提供超过 1 个标签,我只想要包含所有标签的内容,而不仅仅是任何标签

我的第一次尝试是做SELECT DISTINCT contentid FROM content INNER JOIN tags WHERE tagid IN (tagList). 显然,这会导致内容具有 ANY 传入的标记值,而不是所有传入的标记值。

阅读后我尝试做一个不存在,但奇怪的是它没有按照我认为的那样工作。我的查询现在是:

SELECT DISTINCT contentid 
FROM content 
WHERE contentid NOT IN (
    SELECT contentid
    FROM content
    LEFT JOIN tags ON tags.contentid = content.contentid AND tags.tagid IN (tagList)
    WHERE tags.tagid IS NULL
)

编辑(在测试以下内容时,我删除了WHERE tags.tagid IS NULL以查看结果,但即使使用它,我也没有得到预期的结果)

如果我运行子查询并在 tagList 中传递特定 contentid 中缺少的单个值,我会在 tagid 中得到一个 NULL 值。因此,它将按预期从父查询中删除。如果我在为特定 contentid 存在的 tagList 中传入单个值,则它不在子查询中,因此存在于父查询中。

如果我传入多个值(一个现有值,一个特定 contentid 缺失),我只会从子查询中获得 1 行,它不是 NULL 行,因此它不会按预期过滤掉它。

我在这里想念什么?而如何做到这一点呢?

标签: postgresql

解决方案


如果我对您的理解正确:“一个内容有很多标签”......那么,给定一个 N 个标签的列表,您希望内容具有(至少)与它们相关联的那些 N 个标签,对吧?

我认为您可以使用这样的STRING_AGG()函数解决此问题...

SELECT
    c.id,
    STRING_AGG(t.value, ', ' ORDER BY t.value) AS "TAG_LIST"
FROM
    content c
    INNER JOIN tag t ON c.id = t.content_id
WHERE
    t.value IN (<tagList>)
GROUP BY
    c.id
HAVING 
    STRING_AGG(t.value, ', ' ORDER BY t.value) = <tagList as CSV in ORDER!>
;

例子:

-- Return those tagged as first message:
SELECT
    c.id,
    STRING_AGG(t.value, ', ' ORDER BY t.value) AS "TAG_LIST"
FROM
    content c
    INNER JOIN tag t ON c.id = t.content_id
WHERE
    t.value IN ('message', 'first')
GROUP BY
    c.id
HAVING 
    STRING_AGG(t.value, ', ' ORDER BY t.value) = 'first, message'
;

我设法准备了一个小小提琴来测试这个概念(不知道那些小提琴能持续多久)


推荐阅读