使用COUNT过滤标记

时间:2014-02-11 23:50:20

标签: mysql database count

我有以下查询根据一系列约束筛选出线程行:

SELECT *
    FROM threads th 
        JOIN v_threads_with_tags AS twt      /*Only if filtering by tags*/
            ON th.thread_id = twt.thread_id
        JOIN v_friends AS f                  /*Only if filtering to threads from friends*/
            ON th.owner_id = f.friend 
        LEFT JOIN v_visible_threads AS v        
            ON v.thread_id = th.thread_id
    WHERE (v.viewer_id = 43 || v.viewer_id IS NULL) 
    && (v.friend_id = 43 || v.friend_id IS NULL)      
    && user = 43;                          
    && tag_name IN ('foo','bar')

部分查询我没有机会测试,但我可以肯定地说标签名称没有被完全过滤。此查询将返回与此类似的结果集(仅列出相关列):

thread_id | tag_name
    1         foo
    1         bar
    2         foo
    3         foo

我想要一个只有thread_id的结果集,它们链接到查询中列出的所有标签,显然我不能有重复项。在上面的例子中,我想要一个只有一个线程#1实例的结果集。

我在stackoverflow上看过类似的问题(请在将其标记为重复之前阅读),虽然提供的解决方案差异很大,但一般路径似乎经常涉及在查询结尾添加以下语句:

HAVING COUNT('tag_name') = 2

我也尝试了以下类似的查询:

SELECT th.thread_id,th.owner_id,th.message,th.time,tag_name,viewer_id,v.friend_id
    FROM threads th 
        LEFT JOIN v_visible_threads AS v
            ON v.thread_id = th.thread_id
    WHERE (v.viewer_id = 43 || v.viewer_id IS NULL) 
    && (v.friend_id = 43 || v.friend_id IS NULL)
    && th.thread_id IN 
    (
        SELECT thread_id FROM v_threads_with_tags
        WHERE tag_name IN ('foo','bar')
        HAVING COUNT(tag_name) = 2
    )

我无法理解COUNT()在其中任何一个中的用法。在此结果集中,列tag_name有四个值,因此无论特定行中tag_name的值是什么,我都希望COUNT(tag_name)返回4。这实际上是它返回的值,因此该语句会导致查询返回一个空集。

尽管如此,我看到这个语句在任何时候都被用来解决这类问题,所以我必须假设每个人都正确地使用它并且我错过了一些东西。

有人可以向我解释我是否正确理解COUNT,以及我可以使用哪些方法来完成查询?

1 个答案:

答案 0 :(得分:1)

如果您希望线程具有所有标记,则无法仅使用where子句获得该标记。相反,按thread_id聚合并计算每个标记的匹配数。返回对于您关心的每个标记至少有一个匹配的线程:

SELECT th.thread_id
FROM threads th JOIN
     v_threads_with_tags twt      /*Only if filtering by tags*/
     ON th.thread_id = twt.thread_id JOIN
     v_friends f                  /*Only if filtering to threads from friends*/
     ON th.owner_id = f.friend LEFT JOIN
     v_visible_threads AS v        
     ON v.thread_id = th.thread_id
WHERE (v.viewer_id = 43 || v.viewer_id IS NULL) and
      (v.friend_id = 43 || v.friend_id IS NULL) and   
     user = 43
group by th.thread_id
having sum(tag_name = 'foo') > 0 and
       sum(tag_name = 'bar') > 0;