这是斯坦福在线数据库课程练习中的一个问题。 找到平均评分最高的电影。返回这些电影标题及其平均评分。使用 SQLite 。
我见过其他人友好建议的解决方案,例如,
但我希望在此理解的是,我现有的解决方案出现在何处以及为何出错。
电影评级表:
rID mID stars ratingDate
201 101 2 2011-01-22
201 101 4 2011-01-27
203 103 2 2011-01-20
203 108 4 2011-01-12
203 108 2 2011-01-30
204 101 3 2011-01-09
205 103 3 2011-01-27
205 104 2 2011-01-22
...
注意:mID表示电影ID,rID表示评论者ID,星号表示评论者排名的分数。
我的第一个想法是使用以下代码获取每部电影的平均分数:
Select mID, avg(stars) AS avg_stars
From Rating
Group by mID
生成的摘要表是
mID avg_stars
101 3.0
103 2.5
104 2.5
106 4.5
107 4.0
108 3.3
然后我想选择得分列的最大值和相关的mID
Select mID, max(avg_stars) AS Max_score
From (
Select mID, avg(stars) AS avg_stars
From Rating
Group by mID) T
我希望得到:
mID Max_score
106 4.5
但相反,我得到了:
mID Max_score
108 4.5
答案 0 :(得分:2)
而不是子查询尝试使用order by并限制第一个结果:
SELECT mID, AVG(stars) AS avg_stars
FROM Rating
GROUP BY mID
ORDER BY avg_stars DESC LIMIT 1;
答案 1 :(得分:2)
您似乎使用MySQL作为DBMS,它允许使用非标准语法:
当您返回mID
而不将其添加到GROUP BY
时,MySQL会返回一行,其中包含最大(平均)和mID的随机值。
这是一个通用的标准SQL解决方案:
Select mID, avg(stars) AS avg_stars
From Rating
Group by mID
having avg(stars) =
( select max(avg_stars) -- find the max of the averages
from
( Select mID, avg(stars) AS avg_stars
From Rating
Group by mID
) T
)
这可能是非常低效的,这就是为什么有几个专有语法扩展的原因。大多数DBMS(但不支持MySQL)支持标准SQL的窗口化聚合函数:
select *
from
(
Select mID, avg(stars) AS avg_stars,
max(avg(stars)) as max_avg
From Rating
Group by mID
) T
where avg_stars = max_avg
编辑:
当您将SQLite添加为DBMS时,我的第二个查询将无效(SQLite也不支持分析函数)。
但是,由于支持WITH
,您可以将#1简化为类似于@ user3580870的查询:
with cte as
( Select mID, avg(stars) AS avg_stars
From Rating
Group by mID
)
select * from cte
where avg_stars =
( select max(avg_stars) -- find the max of the averages
from cte
);
这仍然符合标准SQL ......
答案 2 :(得分:1)
也许一个WITH子句可以做到这一点。目前无法访问要测试的实时数据库,但查询应如下所示:
WITH sq AS
(SELECT mID, avg(stars) AS avg_stars FROM rating GROUP BY mID)
SELECT mId,avg_stars FROM sq t1 JOIN
(SELECT max(avg_stars) AS max_avg FROM sq) t2
ON t1.avg_stars = t2.max_avg;
SQLite支持3.8.3版的WITH子句。该代码实际上是在问题中的数据上测试的。它还使计算明显比其他解决方案更有效(尽管它们可能通过一些智能查询分析进行优化)。此外,它是最清晰的,WITH
条款可以轻松提供进一步扭曲的路径。
答案 3 :(得分:1)
这只是@SMA's答案的延伸。
如果要将重复记录视为单个实体,可以使用以下查询
SELECT mID,AVG(stars)
FROM Rating
WHERE AVG(stars) IN (
(SELECT AVG(stars)
FROM Rating
GROUP BY mID
ORDER BY avg_stars DESC LIMIT 1)
)
GROUP BY mID
上述查询可能不是优化查询。