【问题标题】:Mysql count records grouped by day in multiple tablesMysql统计多个表中按天分组的记录
【发布时间】:2012-01-04 00:33:05
【问题描述】:

我的数据库有新闻文章和博客文章。两者的主键都是在两个表中唯一的 ItemID。

文章位于包含以下字段的表格中

  • item_id
  • 标题
  • 身体
  • 发布日期

blogposts 表包含以下字段

  • item_id
  • 标题
  • 身体
  • 发布日期

两个表都有额外的独特字段。

我有第三个表,其中包含有关文章和帖子的元信息。

items 表包含以下字段

  • item_id
  • source_id
  • ...

每篇博文和文章在 items 表中都有一条记录,在其各自的表中都有一条记录。

我想要做的是构建一个查询来计算每天发布的项目数量。我可以使用按 date_posted 分组的计数为一个表执行此操作,但如何在一个查询中组合文章和帖子计数

【问题讨论】:

    标签: mysql sql count


    【解决方案1】:

    类似于 Dems,但稍微简单一些:

    select date_posted, count(*)
    from (select date_posted from article union all
          select date_posted from blogposts) v
    group by date_posted
    

    【讨论】:

    • +1 : 我无法在 MySQL 上测试,但在 SQL Server 上测试时优化得非常好(我没想到)。
    • 注意:还假设索引以date_posted 作为第一个字段以获得最佳性能。
    【解决方案2】:

    您可以通过两种方式做到这一点。
    1. 将所有内容连接在一起,然后聚合(参见 Tom H 的回答)。
    2. 聚合每个表,将它们联合起来,然后再次聚合。

    选项 1 可能看起来更短,但意味着您可能不会从根表上的 INDEX 中受益(因为它们必须为 JOIN 重新排序)。所以我将展示选项 2,这是您前进的方向。

    SELECT
      date_posted,
      SUM(daily_count) AS daily_count
    FROM
      (
       SELECT date_posted, COUNT(*) AS daily_count FROM article   GROUP BY date_posted
       UNION ALL
       SELECT date_posted, COUNT(*) AS daily_count FROM blogposts GROUP BY date_posted
      )
      AS combined
    GROUP BY
      date_posted
    

    这应该是最快的,前提是您在每个表上都有一个索引,其中date_posted 是索引中的first 字段。否则,表格仍需要重新排序以进行聚合。

    【讨论】:

    • 请记住,对于第二种解决方案,某些聚合组合起来有点棘手。例如,平均值。不过就数而言,这是一个很好的解决方案。
    • 一个“小”棘手,是的。但是因为您可以同时返回 SUM(value) 和 COUNT(*),所以您可以进行平均。你甚至可以做 STDev(平方和)等。但只要数据格式合适,Mark Ba​​nnister 的答案在所有情况下都更简单。
    【解决方案3】:

    我会为此使用不同的表格设计,包括类型和子类型。您的 Items 表有一个单列主键,Blog_Posts 和 Articles 表的主键与 Items 表的外键相同。这将使这样的事情变得非常容易,并且还有助于确保数据完整性。

    对于您现有的设计,您最好的选择可能是这样的:

    SELECT
        I.item_id,
        I.source_id,
        COALESCE(A.date_posted, B.date_posted) AS date_posted,
        COUNT(*) AS date_count
    FROM
        Items I
    LEFT OUTER JOIN Articles A ON
        A.item_id = I.item_id AND
        I.source_id = 'A'  -- Or whatever the Articles ID is
    LEFT OUTER JOIN Blog_Posts B ON
        B.item_id = I.item_id AND
        I.source_id = 'B'  -- Or whatever the Blog_Posts ID is
    GROUP BY
        I.item_id,
        I.source_id,
        COALESCE(A.date_posted, B.date_posted)
    

    您也可以尝试使用UNION

    SELECT
        SQ.item_id,
        SQ.source_id,
        SQ.date_posted,
        COUNT(*) AS date_count
    FROM
        (
            SELECT I1.item_id, I1.source_id, A.date_posted
            FROM Items I1
            INNER JOIN Articles A ON A.item_id = I1.item_id
            WHERE I1.source_id = 'A'
            UNION ALL
            SELECT I2.item_id, I2.source_id, B.date_posted
            FROM Items I2
            INNER JOIN Articles B ON B.item_id = I2.item_id
            WHERE I2.source_id = 'B'
        )
    

    【讨论】:

      【解决方案4】:
      select item_id, date_posted from blogposts where /* some conditions */
      union all select item_id, date_posted from articles where /* some conditions */
      

      您可能需要将其放入子查询中,如果您愿意,可以在运行group by 时将其与其他表连接起来。但重点是union 是您用来组合来自不同表的相似数据的运算符。 union all 告诉数据库你不需要它来合并重复记录,因为你知道这两个表永远不会共享一个 item_id,所以它会快一点(可能)。

      【讨论】:

      • 我试图做一个联合,但我实际上想要做的是,在 OP 中并不清楚是否结合计数的结果。所以这两个选择是select count(item_id) from blogposts group by dateselect count(item_id_ from articles group by date
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      • 2014-12-19
      • 2013-02-04
      • 2012-05-10
      • 2010-10-01
      • 2019-07-18
      相关资源
      最近更新 更多