我无法在stackoverflow上找到我的问题的答案。我有一个跨越3个表的查询:
newsitem
+------+----------+----------+----------+--------+----------+
| Guid | Supplier | LastEdit | ShowDate | Title | Contents |
+------+----------+----------+----------+--------+----------+
newsrating
+----+----------+--------+--------+
| Id | NewsGuid | UserId | Rating |
+----+----------+--------+--------+
usernews
+----+----------+--------+----------+
| Id | NewsGuid | UserId | ReadDate |
+----+----------+--------+----------+
Newsitem显然包含newsitems,newsrating包含用户为newsitems提供的评级,而usernews包含用户阅读newsitem的日期。
在我的查询中,我想获取每个newsitem,包括该newsitem的评级数和平均评级,以及当前用户读取newsitem的次数。
到目前为止我所拥有的是:
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小提琴:http://sqlfiddle.com/#!9/c8add/8
count()调用都不会返回我想要的数字。 numberofratings应该返回该newsitem的评级总数(由所有用户)。 numberofreads应返回该newsitem的当前用户的读取次数。
因此,带有guid d104c330-c319-40e8-8be3-a7c4f549d35c的newsitem对于userid = 3的当前用户应该有2个等级和3个读取。
我尝试了条件计数和总和,但还没有成功。如何实现这一目标?
答案 0 :(得分:2)
我看到的主要问题是你将两个表加在一起,这意味着你将有效地乘以两个数字,这就是为什么你的计数不正确。例如,如果Newsitem已被用户读取3次并被8位用户评分,那么您最终将获得24行,因此它看起来已被评为24次。您可以在DISTINCT
的评分ID中添加COUNT
,以便更正该问题。平均值应该不受影响,因为1和2的平均值与1,1,2和1的平均值相同。 2(例如)。
然后,您可以通过将用户ID添加到JOIN
条件来处理读取(因为它是OUTER JOIN
它不应导致任何结果丢失)而不是CASE
语句对于COUNT
,您可以对来自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
答案 1 :(得分:2)
我和Tom一起使用子查询来计算用户数。
<强> SQL Fiddle Demo 强>
SELECT NI.guid,
NI.supplier,
COUNT(NR.ID) as numberofratings,
AVG(NR.rating) as rating,
user_read as numberofreads
FROM newsitem NI
LEFT JOIN newsrating NR
ON NI.guid = NR.newsguid
LEFT JOIN (SELECT NewsGuid, COUNT(*) user_read
FROM usernews
WHERE UserId = 3 -- use a variable @user_id here
GROUP BY NewsGuid) UR
ON NI.guid = UR.NewsGuid
GROUP BY NI.guid,
NI.supplier,
numberofreads;