MySQL:每行返回几个项目的计数

Posted

技术标签:

【中文标题】MySQL:每行返回几个项目的计数【英文标题】:MySQL: return count of several items for each row 【发布时间】:2021-02-12 02:10:35 【问题描述】:

我有一张列出一些项目的表格。 然后我有 3 个不同的表,每个表都记录了针对某个项目执行的各种操作,以及日期和执行者:

Table "items":
item_id, title, description

Table "item_views":
item_id, date, user_id

Table "item_follows":
item_id, date, user_id

Table "item_likes":
item_id, date, user_id

我正在尝试提出一个查询,该查询将列出每个项目,以及它们在其他 3 个表中的每个表中被引用的次数。

它只需要计算两个给定日期之间的操作,我还需要能够按任何计数器排序。

所以我会给它两个日期并说“按喜欢排序”,它会返回如下内容:

item id     item title     views_counter    follows_counter      likes_counter
item1       Some title     0                5                    6
item2       Some title     4                0                    4
item3       Some title     3                2                    0

任何建议将不胜感激,在此先感谢!

【问题讨论】:

【参考方案1】:

对找到计数的子查询使用左连接:

SELECT
    i.item_id,
    i.title,
    COALESCE(v.view_cnt, 0)   AS views_counter,
    COALESCE(f.follow_cnt, 0) AS follows_counter,
    COALESCE(l.like_cnt, 0)   AS likes_counter
FROM items i
LEFT JOIN
(
    SELECT item_id, COUNT(*) AS view_cnt
    FROM item_views
    GROUP BY item_id
) v
    ON v.item_id = i.item_id
LEFT JOIN
(
    SELECT item_id, COUNT(*) AS follow_cnt
    FROM item_follows
    GROUP BY item_id
) f
    ON f.item_id = i.item_id
LEFT JOIN
(
    SELECT item_id, COUNT(*) AS like_cnt
    FROM item_likes
    GROUP BY item_id
) l
    ON l.item_id = i.item_id

【讨论】:

非常感谢,这正是我想要的!它也让我可以灵活地添加各种其他过滤和排序。【参考方案2】:

您可以使用union all 和聚合:

select i.*,
       sum(which = 'view') as views,
       sum(which = 'follow') as follows,
       sum(which = 'like') as likes
from items i left join
     ((select item_id, 'view' as which
       from item_views
      ) union all
      (select item_id, 'follow' as which
       from item_follows
      ) union all
      (select item_id, 'like' as which
       from item_likes
      )
     ) vfl
     on i.item_id = vfl.item_id
group by i.item_id;

【讨论】:

呃,左加入多个嵌套组比 IMO 好得多 @charlieface 为什么? @Strawberry 诚然,我不太了解 mysql 优化器的工作原理,但 SQL Server 会遇到困难。它可能会在连接之前联合表,和/或强制嵌套循环(与散列或合并相反),而另一个答案中的左连接语法不会有同样的问题。再加上它在美学上对我来说看起来不太好(个人意见) @Charlieface 。 . .你的评论绝对不是真的。事实上,如果外部查询在子查询中的列上进行过滤,SQL Server 与这个union all 版本一起工作得更好。优化器足够聪明,可以将过滤器投射到子查询中执行union all 通常是的,它会将谓词下推,但它也可以用左连接/分组语法做同样的事情,IME 语法更容易被优化器转换。求和在这里的性能也较低,因为您需要检查每一行将其添加到哪个总和,而左连接将求和推到连接下方。您可能仍然可以通过在每个联合表中进行分组来优化您的版本。

以上是关于MySQL:每行返回几个项目的计数的主要内容,如果未能解决你的问题,请参考以下文章

返回peewee ORM中分组项目的计数

如何在 MySQL 中为行保留一个计数器

mySQL 返回错误的计数结果

MySQL查询仅返回具有计数的重复条目

Mysql:计数,分组,但返回所有结果

结合连接和计数的MySQL语句?