【问题标题】:Mysql count() not summing with two table JOIN and GROUP BY, in tagging scheme在标记方案中,Mysql count() 不与两个表 JOIN 和 GROUP BY 求和
【发布时间】:2020-08-29 00:40:24
【问题描述】:

我有一个带有关联标签的问题场景——比如这里的 StackOverflow。我想列出与某个问题相关的所有标签以及每个标签的计数,该计数告诉其他问题使用/引用同一标签的次数。

标签表: tag_id , tag_name(tag_name 是唯一的)

TAGS CROSS REFERENCE TABLE:tag_id、question_id(tag_id 引用tags 表中的tag_id,以及questions 表中的question_id)。

问题表:question_id,问题。

我的代码列出了与特定 question_id 关联的所有标签,但每个标签的总使用量的 count()/num 始终为“1”,但应该总计不同的数字...

$question_id = 268;
$sql = 'SELECT tags.tag_id, tag_name, count(tags.tag_id) AS num
        FROM tags LEFT JOIN tags_x 
        ON tags.tag_id = tags_x.tag_id 
        WHERE tags_x.question_id = ? 
        GROUP BY tags.tag_name';    
$stmt = $db->prepare($sql);
$stmt->execute([$question_id]); 
$result = $stmt->fetchAll(pdo::FETCH_ASSOC);
$out = '';
foreach($result as $row){
    $tag_id = $row['tag_id'];
    $tag_name = $row['tag_name'];
    $num = $row['num'];//count of all items referencing same tagname
    echo $tag_id.' - '.$tag_name.' - '.$num.'<br>';
}

【问题讨论】:

    标签: mysql sql join group-by count


    【解决方案1】:

    当您在SELECT 子句中包含tags.tag_id 时,MySql 将隐式包含它作为GROUP BY 的一部分。这违反了 ansi 标准,顺便说一句,它根本不允许这个查询。

    也许你想要count(tags_x.tag_id)

    SELECT tags.tag_id, tag_name, count(tags_x.tag_id) AS num
    FROM tags 
    LEFT JOIN tags_x ON tags.tag_id = tags_x.tag_id 
    WHERE tags_x.question_id = ? 
    GROUP BY tags.tag_id, tags.tag_name
    

    【讨论】:

    • 尝试了你上面的代码修改,得到了同样的结果。
    【解决方案2】:

    一个选项使用相关子查询来计算每个标签的问题数。我希望效率更高,因为它避免了外部聚合的需要:

    select 
        t.tag_id, 
        t.tag_name, 
        (select count(*) from tags_x tx1 where tx1.tag_id = t.tag_id) no_questions
    from tags t
    inner join tags_x tx on tx.tag_id = t.tag_id
    where tx.question_id = ? 
    

    这会为您提供每个标签的问题总数。如果你想对当前问题以外的问题进行计数,可以从结果中减去 1,或者细化子查询的where 条件:

    select 
        t.tag_id, 
        t.tag_name, 
        (select count(*) from tags_x tx1 where tx1.tag_id = t.tag_id and tx1.question_id <> tx.question_id) no_questions
    from tags t
    inner join tags_x tx on tx.tag_id = t.tag_id
    where tx.question_id = ? 
    

    【讨论】:

    • 顶级代码完美运行!子查询 - 不知道你能做到这一点!非常感谢!
    【解决方案3】:

    我在想我们需要 两个 引用 tag_x 交叉引用表,一个来获取与我们的问题相关的标签,另一个来获取 all对同一标签的引用。

    要返回tag_name,我们需要加入tag 表。

    类似这样的:

    SELECT t.tag_name
         , t.tag_id
         , COUNT(c.tag_id) AS cnt_references
      FROM tags_x q
      JOIN tags_x c
        ON c.tag_id = t.tag_id
      JOIN tags 
        ON t.tag_id = q.tag_id
     WHERE q.question_id = ?
     GROUP
        BY t.tag_name
         , t.tag_id
     ORDER
        BY t.tag_name
         , t.tag_id
    

    如果我们不需要返回tag_name,我们可以避免连接到tag 表,而只需执行以下操作:

    SELECT q.tag_id
         , COUNT(c.tag_id) AS cnt_references
      FROM tags_x q
      JOIN tags_x c
        ON c.tag_id = t.tag_id
     WHERE q.question_id = ?
     GROUP
        BY q.tag_id
     ORDER
        BY q.tag_id
    

    这样做可能会更快,在一个内联视图中,然后稍后加入tag 表。这应该给出与第一个查询相同的结果。

    SELECT t.tag_name
         , t.tag_id
         , r.cnt_references
      FROM ( -- inline view to count references, one row per tag_id
             SELECT q.tag_id
                  , COUNT(c.tag_id) AS cnt_references
               FROM tags_x q
               JOIN tags_x c
                 ON c.tag_id = t.tag_id
              WHERE q.question_id = ?
              GROUP
                 BY q.tag_id
           ) r
      JOIN tags t
        ON t.tag_id = r.tag_id
     ORDER
        BY t.tag_name
         , t.tag_id
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      • 1970-01-01
      • 2014-10-22
      • 2023-03-18
      • 1970-01-01
      • 2021-04-01
      相关资源
      最近更新 更多