First, I'd used a derived table to calculate the statistics. This makes it easier to convert nulls to zero if you want (although if we're using an Inner Join as I am here, you couldn't need to use Coalesce on the TotalReviews).
Select m.*
, Coalesce(MovieStats.TotalReviews, 0) As TotalReviews
, Coalesce(MovieStats.AverageRating, 0) As AverageRating
From Movie As m
Join (
Select R1.MovieId
, Count(*) As TotalReviews
, AVG( (r.StoryRating + r.HumorRating + r.ActingRating) / 3 ) As AverageRating
From MovieReview As r1
Group By R1.MovieId
) As MovieStats
On MovieStats.MovieId = m.Id
Where MovieStats.AverageRating Between @LowestRating And @HighestRating
The only issue here is that by putting our filter in the Where clause, it means we must have MovieReview records with AverageRating values in given range.
Select m.*
, Coalesce(MovieStats.TotalReviews, 0) As TotalReviews
, Coalesce(MovieStats.AverageRating, 0) As AverageRating
From Movie As m
Left Join (
Select R1.MovieId
, Count(*) As TotalReviews
, AVG( (r.StoryRating + r.HumorRating + r.ActingRating) / 3 ) As AverageRating
From MovieReview As r1
Group By R1.MovieId
) As MovieStats
On MovieStats.MovieId = m.Id
And MovieStats.AverageRating Between @LowestRating And @HighestRating
This will return zero in those instances where there are no movie ratings or the movie ratings that do exist are outside the passed range.
Yet another possibility is to filter on values that have Reviews and force those to have average ratings in the passed range:
Select m.*
, Coalesce(MovieStats.TotalReviews, 0) As TotalReviews
, Coalesce(MovieStats.AverageRating, 0) As AverageRating
From Movie As m
Left Join (
Select R1.MovieId
, Count(*) As TotalReviews
, AVG( (r.StoryRating + r.HumorRating + r.ActingRating) / 3 ) As AverageRating
From MovieReview As r1
Group By R1.MovieId
) As MovieStats
On MovieStats.MovieId = m.Id
Where MovieStats.MovieId Is Null
Or ( MovieStats.AverageRating Between @LowestRating And @HighestRating )