【问题标题】:MYSQL group by and inner joinMYSQL group by 和内部连接
【发布时间】:2013-01-08 11:03:59
【问题描述】:

我有一个文章表,其中包含每天的文章浏览量。将创建一条新记录来保存每篇文章的每一天的计数。

下面的查询获取文章 ID 和总浏览量排名前 5 的文章 ID 的所有时间:

SELECT article_id, 
SUM(article_count) as cnt
FROM article_views
GROUP BY article_id
ORDER BY cnt DESC
LIMIT 5 

我还有一个单独的文章表,其中包含所有文章字段。我想修改上面的查询以加入文章表并为每个文章 ID 获取两个字段。我尝试在下面执行此操作,但计数返回错误:

SELECT article_views.article_id, SUM( article_views.article_count ) AS cnt, articles.article_title, articles.artcile_url
FROM article_views
INNER JOIN articles ON articles.article_id = article_views.article_id
GROUP BY article_views.article_id
ORDER BY cnt DESC
LIMIT 5

我不确定我到底做错了什么。我需要做一个子查询吗?

【问题讨论】:

    标签: mysql subquery inner-join


    【解决方案1】:

    articles.article_title, articles.artcile_url 添加到GROUP BY 子句中:

    SELECT 
      article_views.article_id, 
      articles.article_title, 
      articles.artcile_url,
      SUM( article_views.article_count ) AS cnt
    FROM article_views
    INNER JOIN articles ON articles.article_id = article_views.article_id
    GROUP BY article_views.article_id,   
             articles.article_title, 
             articles.artcile_url
    ORDER BY cnt DESC
    LIMIT 5;
    

    您没有得到正确结果集的原因是,当您选择未包含在 GROUP BYSELECT 子句中的聚合函数中的行时,MySQL 会选择随机值。

    【讨论】:

    • 令我印象深刻的是,您似乎对数据结构的了解比问题中介绍的要多得多。就一点。 MySQL 不会选择 random 值。它选择一个 任意 值。 Random 表示可以选择任何值。事实上,它几乎总是第一条记录中的值——但你不能依赖这个事实。
    • 如果article 表中恰好有行匹配article_idarticle_titlearticle_url,(即不保证这三者的组合是唯一的),那么与原始查询相比,此查询返回的计数仍受“关闭”的影响。 (这确实让人想知道为什么“article”表中名为“article_id”的列中会有任何重复值。)
    【解决方案2】:

    您正在使用称为隐藏列的 MySQL (mis) 功能,因为文章标题不在 group by 中。但是,这可能会也可能不会导致您的问题。

    如果计数错误,那么我认为您在文章表中有重复的article_id。您可以通过以下方式检查:

    select article_id, count(*) as cnt
    from articles
    group by article_id
    having cnt > 1
    

    如果出现任何问题,那就是你的问题。如果他们都有不同的标题,那么按标题分组(如 Mahmoud 建议的那样)将解决问题。

    如果没有,修复它的一种方法如下:

    SELECT article_views.article_id, SUM( article_views.article_count ) AS cnt, articles.article_title, articles.artcile_url
    FROM article_views INNER JOIN
         (select a.* from articles group by article_id) articles
         ON articles.article_id = article_views.article_id
    GROUP BY article_views.article_id
    ORDER BY cnt DESC
    LIMIT 5
    

    这会为文章选择一个任意标题。

    【讨论】:

    • 使用这种方法,cnt 值不会因article_id 值重复出现在articles 表中而被夸大;以这种方式隔离查询似乎更好。
    【解决方案3】:

    您的查询对我来说基本上是正确的......

    cnt 返回的值将取决于article_id 列在articles 表中的唯一性。我们假设它是主键,并且没有架构定义,这只是一个假设。)

    此外,我们可能假设表之间存在外键,也就是说,articles_view 表中没有与行上的 article_id 值不匹配的 article_id 值来自articles 表。


    要检查“孤儿” article_id 值,请运行如下查询:

    SELECT v.article_id
      FROM articles_view v
      LEFT
      JOIN articles a
        ON a.article_id = v.article_id
     WHERE a.article_id IS NULL
    

    要检查文章中的“重复”article_id 值,请运行如下查询:

    SELECT a.article_id
      FROM articles a
     GROUP BY a.article_id
    HAVING COUNT(1) > 1 
    

    如果这些查询中的任何一个返回行,这可能是对您观察到的行为的解释。

    【讨论】:

      猜你喜欢
      • 2021-02-14
      • 2019-01-15
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      相关资源
      最近更新 更多