【问题标题】:Cannot filter null even has implemented in where function即使在 where 函数中实现了也无法过滤 null
【发布时间】:2019-08-28 12:44:55
【问题描述】:

三张表:-Rating (rID, mID, stars, ratingDate) Movie (mID, title, year, director)Reviewer (rID, name)

找出 1980 年之前发行的电影的平均评分与 1980 年之后发行的电影的平均评分之间的差异。

(确保计算每部电影的平均评分,然后计算 1980 年之前和之后的电影的平均值。不要只计算 1980 年之前和之后的总体平均评分。)

但总是有null,即使我在where函数中过滤了null

''''
select r.mID,sum(stars),
count(case when year>1980 and stars is not null then stars end )as "numaf",
count(case when year<1980 and stars is not null then stars end )as "numbf",
sum(case when year>1980 and stars is not null then stars end )as "sumaf",
sum(case when year<1980 and stars is not null then stars end )as "sumbf",
(("sumaf"/"numaf")-("sumbf"/"numbf")) as "difof"
from Rating r left join movie m on r.mID = m.mID 
where stars is not null
group by r.mID
''''

and this is output, always has "NULL":
101 9   0   3   <NULL>  9   <NULL>
103 5   0   2   <NULL>  5   <NULL>
104 5   2   0   5   <NULL>  <NULL>
106 9   0   2   <NULL>  9   <NULL>
107 8   2   0   8   <NULL>  <NULL>
108 10  3   0   10  <NULL>  <NULL>

【问题讨论】:

  • 结合大家(下)的建议,问题已经解决,非常感谢! select max(p.avgV)-min(P.avgV) from(select avg(o.avgS) as avgV, case when year &gt; 1980 then 1 else 0 end as yearIndicator from (select mID,avg(stars)as avgS from rating group by mID) as o join movie m on o.mID = m.mID group by yearIndicator) as P
  • 为什么会有这么多空值是因为对于某些电影,它们在 1980 年后才出现,所以即使我在连接两个表时过滤了空值,总和也必须为空。

标签: sql sqlite syntax-error


【解决方案1】:

电影的平均评分是:

select r.mID, avg(stars) as avg_stars
from Rating r 
group by r.mID;

然后,要回答这个问题,您可以将其加入到电影中并使用条件聚合:

select avg(case when year < 1980 then avg_stars) as avg_stars_pre1980,
       avg(case when year > 1980 then avg_stars) as avg_stars_post1980,
       (avg(case when year < 1980 then avg_stars) -
        avg(case when year > 1980 then avg_stars) a
       ) as diff       
from (select r.mID, avg(stars) as avg_stars
      from Rating r 
      group by r.mID
     ) r join
     movie m
     on r.mID = m.mID 
group by r.mID;

您获得NULL 的原因是因为您认为您正在划分SELECT 中定义的列别名。但是,您实际上是在划分字符串。所以:

(("sumaf"/"numaf")-("sumbf"/"numbf")) as "difof"

只是:

(('sumaf'/'numaf')-('sumbf'/'numbf')) as difof

字符串被解释为数字,在数字常量中,前导数字转换为数字。这些没有前导数字,因此这些值都是0 - 导致被零除。 MySQL 返回NULL 除以零而不是产生错误。

【讨论】:

  • 非常感谢!但是我仍然很困惑为什么我在这里得到了这么多空值,即使我已经在 where 和 case 中过滤了它。
  • @Olly 。 . .如果某个时间段内没有电影,则sum() 返回NULL。我在答案的最后一列中解释了这个问题。
  • 非常感谢!我想我知道为什么,也许对于某些电影 id,1980 年之后就没有了。所以 sum 仍然显示为 null。
【解决方案2】:

要获得 1980 年之前和之后的电影的平均评分,您可以执行以下操作:

SELECT SUM(avgRating)/Count(mID), yearSection
FROM (
    SELECT 
       r.mid,
       round(sum(stars),2)/count(r.mID) as avgRating,
       case when year > 1980 then 1 else 0 end as yearSection
from Rating r left join movie m on r.mID = m.mID 
where stars is not null
group by r.mID
     )AS foo
GROUP BY yearSection

这不会产生任何空值。此外,您应该需要将总和四舍五入为小数,否则您的平均值将不正确。

【讨论】:

  • 非常感谢!这确实可以给出这个问题的答案。但是我仍然很困惑为什么我过滤它时在这里得到了 null。
  • 是的 - 但我想向您展示一种更简洁的方法来解决这个问题:)
  • 非常感谢!我是这样解决的:select max(p.avgV)-min(P.avgV) from(select avg(o.avgS) as avgV, case when year &gt; 1980 then 1 else 0 end as yearIndicator from (select mID,avg(stars)as avgS from rating group by mID) as o join movie m on o.mID = m.mID group by yearIndicator) as P
猜你喜欢
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-31
  • 1970-01-01
  • 1970-01-01
  • 2022-10-05
  • 2018-10-04
  • 1970-01-01
相关资源
最近更新 更多