1

我有三个表,posts, tags, & postTags。正如您可能猜到的那样,posts保存有关博客文章的信息,tags保存有关系统上正在使用的标签的信息,并保存和postTags之间的关系。poststags

现在,假设我知道tagID我正在寻找的每个标签的 s 以及我不知道的标签,什么是合适的,什么是合适的查询来获取所有posts符合tagID我指定的所有 s标准的在一个列表上,而没有我在另一个列表上指定的内容?

我可以解决的一种方法是:

SELECT
    `posts`.*,
    CONCAT(',', GROUP_CONCAT(`postTags`.`tagID`), ',') AS `pTags`
FROM
    `posts`
INNER JOIN
    `postTags`
    ON
    `postTags`.`postID` = `posts`.`postID`
GROUP BY
    `posts`.`postID`
HAVING
    `pTags` LIKE '%,2,%'
    AND
    `pTags` LIKE '%,3,%'
    AND
    `pTags` NOT LIKE '%,5,%'

此查询将选择所有已标记为 tagID 2 和 3 且未标记为 tagID 5 的帖子。但这似乎很慢,尤其是当数据被大量标记过滤时。

编辑

SQL小提琴

4

3 回答 3

2

您可以尝试使用 EXISTS 策略优化查询:

SELECT
    `posts`.*
FROM
    `posts`
WHERE
    EXISTS (
      SELECT 1 FROM `postTags` 
      WHERE `postTags`.`postID` = `posts`.`postID`
        AND `postTags`.`tagID` = 2
    )
    AND
    EXISTS (
      SELECT 1 FROM `postTags` 
      WHERE `postTags`.`postID` = `posts`.`postID`
        AND `postTags`.`tagID` = 3
    )    
    AND NOT EXISTS (
      SELECT 1 FROM `postTags` 
      WHERE `postTags`.`postID` = `posts`.`postID`
        AND `postTags`.`tagID` = 5
    )    
于 2013-05-23T10:46:29.357 回答
1

我相信它会带来你想要的帖子。

SELECT 
    p.*, GROUP_CONCAT(pt.tagID)    
FROM
    posts p
    inner join postTags pt on p.postID  = pt.postID
WHERE
not exists (
    SELECT
        1
    FROM
        Tags t
    WHERE
        t.tagID in (2,3)
        AND not exists
        (
           select 1 from postTags pt where pt.postID = p.postID and pt.tagID = t.tagID
        )
)
and not exists(
    SELECT
        1
    FROM
        Tags t
    WHERE
        t.tagID in (5)
        AND exists
        (
           select 1 from postTags pt where pt.postID = p.postID and pt.tagID = t.tagID
        )
)
GROUP BY p.postID
于 2014-11-03T23:33:22.713 回答
1

我会针对几个子选择进行连接,避免相关的子查询。

类似于以下内容(不确定您是否需要 SELECT 中的标签串联列表,但暂时将其留在那里)

SELECT `posts`.*,
    CONCAT(',', Sub1.TagList, ',') AS `pTags`
FROM `posts`
INNER JOIN (
    SELECT postID, GROUP_CONCAT(`postTags`.`tagID`) AS TagList, COUNT(*) AS TagCount 
    FROM postTags 
    WHERE tagID IN (2, 3) 
    GROUP BY postID 
    HAVING TagCount = 2
) Sub1
ON posts.postID = Sub1.postID
LEFT OUTER JOIN (
    SELECT postID
    FROM postTags 
    WHERE tagID IN (5) 
) Sub2
ON posts.postID = Sub2.postID
WHERE Sub2.postID IS NULL
于 2013-05-23T11:35:11.740 回答