有没有更好的方法来制定此 SQL 查询?

Is there a better way to formulate this SQL query?

我是 SQL 宇宙的新手,我遇到了这个我能够完成的提示,但我不得不想象我错过了一个更直接和直观的解决方案。我的解决方案 returns SQLite 中的正确响应舍入到小数点后 10 位以上,但技术上与报告的解决方案不匹配。我很感激任何见解。

提示: 找出 1980 年以前上映的电影的平均评分 ["stars"] 和 1980 年以后上映的电影的平均评分之间的差异。(前后平均值的差值。)

数据库包含 3 个表,其中包含以下列(相关性已简化):

movie| mID*, year
reviewer| rID*, name
rating| rID*, mI*, stars
"mavg" is my own aliased aggregation

select distinct(
        (select avg(mavg)
         from(
               (select *, avg(stars) as mavg
                from rating
                group by mID) join movie using(mID) )
                where year < 1980)    -
        (select avg(mavg)
         from(
               (select *, avg(stars) as mavg
                from rating
                group by mID) join movie using(mID) )
                where year >= 1980)
              )
from rating
;

您可以在此处使用以下单个查询:

SELECT AVG(CASE WHEN m.year < 1980 THEN r.stars END) -
       AVG(CASE WHEN m.year >= 1980 THEN r.stars END) AS mavg
FROM rating r
INNER JOIN movie m ON m.mID = r.mID;

让我们看看您的子查询:

select *, avg(stars) as mavg
from rating
group by mID

这是一个无效的查询。使用 GROUP BY mid 你说你想聚合你的行以获得每个 mID 的一个结果行。但是,您不仅 select 平均评分,而且 table (SELECT *) 中的所有列。这些列之一是 stars。当一个 mID 有很多行时,如何 select 将星号列排成一行?大多数 DBMS 在此处报告语法错误。 SQLite 会从 mID 的任意行中任意挑选一颗星星。因此,虽然这在 SQLite 中被认为是有效的,但它不符合标准 SQL,您不应该编写此类查询。

你加入电影的结果(每部电影的平均值)table。然后你 select 所需年份电影的平均评分。这做得很好,但是您可以将该限制(连接或 IN 子句或 EXISTS 子句)直接放入子查询中,以便只计算您想要的电影的平均值,而不是计算所有平均然后只保留一些电影而忽略其他电影。但这是一个小细节。

然后用旧平均值减去新平均值。这意味着您从一个值中减去另一个值,最终得到您想要显示的值。但是,您不是仅仅 selecting 这个值 (SELECT (...) - (...)),而是将这个值与评级 table (SELECT (...) - (...) FROM rating) 联系起来,没有明显的原因,因此 select评级 table 中的行数与期望值的频率相同。然后您会注意到这一点并应用 DISTINCT 来删除您刚刚自己不必要地创建的行。 DISTINCT 非常非常经常地表示查询编写不当。当您认为需要 DISTINCT 时,问问自己是什么让这成为必要。重复行从何而来?你自己创造的吗?修改这个。

查询可以这样写:

select
  avg(case when m.year < 1980 then r.movie_rating end) -
  avg(case when m.year >= 1980 then r.movie_rating end) as diff
from
(
  select mid, avg(stars) as movie_rating
  from rating
  group by mid
) r
join movie m using (mid);

在聚合函数中使用 case 表达式称为条件聚合,通常是处理不同聚合时的首选解决方案。