MYSQL group by 和内部连接
Posted
技术标签:
【中文标题】MYSQL group by 和内部连接【英文标题】:MYSQL group by and inner join 【发布时间】: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
我不确定我到底做错了什么。我需要做一个子查询吗?
【问题讨论】:
【参考方案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 BY
或 SELECT
子句中的聚合函数中的行时,mysql 会选择随机值。
【讨论】:
令我印象深刻的是,您似乎对数据结构的了解比问题中介绍的要多得多。就一点。 MySQL 不会选择 random 值。它选择一个 任意 值。 Random 表示可以选择任何值。事实上,它几乎总是第一条记录中的值——但你不能依赖这个事实。 如果article
表中恰好有行匹配article_id
、article_title
和article_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
如果这些查询中的任何一个返回行,这可能是对您观察到的行为的解释。
【讨论】:
以上是关于MYSQL group by 和内部连接的主要内容,如果未能解决你的问题,请参考以下文章
oracle sql中的group by表达式的内部连接[重复]