mysql - 带连接的 Sql 条件计数

标签 mysql sql

我在 stackoverflow 上找不到问题的答案。我有一个跨越 3 个表的查询:

newsitem
+------+----------+----------+----------+--------+----------+
| Guid | Supplier | LastEdit | ShowDate |  Title | Contents |
+------+----------+----------+----------+--------+----------+
newsrating
+----+----------+--------+--------+
| Id | NewsGuid | UserId | Rating |
+----+----------+--------+--------+
usernews
+----+----------+--------+----------+
| Id | NewsGuid | UserId | ReadDate |
+----+----------+--------+----------+

Newsitem 显然包含新闻站点,新闻评级包含用户对新闻站点的评分,而 usernews 包含用户阅读新闻站点的日期。

在我的查询中,我想获取每个新闻网站,包括该新闻网站的评分数量和平均评分,以及当前用户阅读该新闻网站的次数。

到目前为止我所拥有的是:

select newsitem.guid, supplier, count(newsrating.id) as numberofratings,
    avg(newsrating.rating) as rating,
    count(case usernews.UserId when 3 then 1 else null end) as numberofreads from newsitem
    left join newsrating on newsitem.guid = newsrating.newsguid
    left join usernews on newsitem.guid = usernews.newsguid
    group by newsitem.guid

我在这里创建了一个sql fiddle :http://sqlfiddle.com/#!9/c8add/8

两个 count() 调用都没有返回我想要的数字。 numberof ratings 应返回该新闻站点的评分总数(所有用户)。 numberofreads 应返回该新闻网站当前用户的阅读次数。

因此,对于 userid = 3 的当前用户,guid 为 d104c330-c319-40e8-8be3-a7c4f549d35c 的 newsitem 应该有 2 个评分和 3 个读取。

我尝试过条件计数和求和,但尚未成功。如何才能做到这一点?

最佳答案

我看到的主要问题是您将两个表连接在一起,这意味着您将有效地乘以两个数字,这就是您的计数不正确的原因。例如,如果 Newsitem 已被用户阅读 3 次并被 8 位用户评分,那么您最终将获得 24 行,因此看起来它已被评分 24 次。您可以将 DISTINCT 添加到您的 COUNT 评分 ID 中,这样就可以解决该问题。平均值应该不受影响,因为 1 和 2 的平均值与 1, 1, 2, & 2 的平均值相同(例如)。

然后,您可以通过将用户 ID 添加到 JOIN 条件(因为它是 OUTER JOIN 它不应该导致任何结果丢失)而不是在为您的 COUNT 编写一个 CASE 语句,然后您可以对 Usernews 中的不同 id 值执行 COUNT 操作。结果查询将是:

SELECT
    I.guid,
    I.supplier,
    COUNT(DISTINCT R.id) AS number_of_ratings,
    AVG(R.rating) AS avg_rating,
    COUNT(DISTINCT UN.id) AS number_of_reads
FROM
    NewsItem I
LEFT OUTER JOIN NewsRating R ON R.newsguid = I.guid
LEFT OUTER JOIN UserNews UN ON
    UN.newsguid = I.guid AND
    UN.userid = @userid
GROUP BY
    I.guid,
    I.supplier

虽然这应该可行,但您可能会从子查询中获得更好的结果,因为上面需要分解结果然后聚合它们,这可能是不必要的。另外,有些人可能会发现下面的内容更清晰一些。

SELECT
    I.guid,
    I.supplier,
    R.number_of_ratings,
    R.avg_rating,
    COUNT(*) AS number_of_reads
FROM
    NewsItem I
LEFT OUTER JOIN
(
    SELECT
        newsguid,
        COUNT(*) AS number_of_ratings,
        AVG(rating) AS avg_rating
    FROM
        NewsRating
    GROUP BY
        newsguid
) R ON R.newsguid = I.guid
LEFT OUTER JOIN UserNews UN ON UN.newsguid = I.guid AND UN.userid = @userid
GROUP BY
    I.guid,
    I.supplier,
    R.number_of_ratings,
    R.avg_rating

关于mysql - 带连接的 Sql 条件计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34657457/

相关文章:

mysql - 当两列具有相同的值时,INSERT WHERE NOT EXISTS 不起作用

php - 查看与您的 mysql 服务器版本相对应的手册,了解使用 near 的正确语法

mysql - 使用 MySQL 触发器替换输入

java - 如何使用jdbc代码手动连接mysql?

php - 你使用 mysql_error($con) 还是 mysql_insert_id($con) 来检查插入结果?

MySQL游标只返回一条记录

mysql - 'headings.heading' 中的未知列 'field list'

sql - 更高效的 SQL 语句来消除我的 n^2 算法?

php - 这个 MySQL IN 子句中的负值有什么问题?

MySQL 使用 CASE AND Group By 进行选择