Nesting Aggregate Functions - SQL - sql

I want to make a SQL query which finds the catagory of awards for movies which has the highest average rating, so for a group of movies which have won a particular award, if they have a higher average rating than any other awards group of movies then it will be returned.
I tried something like this:
SELECT MAX(AVG(m."Rating"))
FROM awards a, movies m
WHERE a."Title" = m."Title"
GROUP BY a."Award"
but it seems that aggregate functions cannot be nested. How can I call the max function on the average ratings for each catagory?

If you are only interested in the value itself, the following should do it:
SELECT MAX(avg_rating)
FROM (
SELECT AVG(m."Rating") as avg_rating
FROM awards a, movies m
WHERE a."Title" = m."Title"
GROUP BY a."Award"
) t
Otherwise Adrian's solution is better.

This will bring your desired result:
SELECT a."Award", AVG(m."Rating")
FROM awards a, movies m
WHERE a."Title" = m."Title"
GROUP BY a."Award"
ORDER by AVG(m."Rating") desc
LIMIT 1
This will allow you not only get the MAX value, but its corresponding Award info

Did you try this?
SELECT MAX(
SELECT AVG(m."Rating")
FROM awards a, movies m
WHERE a."Title" = m."Title"
GROUP BY a."Award"
)

Another way is to use windowed MAX:
SELECT MAX(AVG(m."Rating")) OVER()
FROM awards a -- proper JOIN syntax
JOIN movies m ON a."Title" = m."Title"
GROUP BY a."Award"
LIMIT 1;
db<>fiddle demo

Related

Get Average in SQL Through Join

I'm just playing around with SQL and I'm trying to do the following.
I have 2 tables and here is their structure:
Movies_metadata Movies
ratings table:
Ratings
As there are many ratings for one movie, what I'd like to do is get the avg rating per movie and have it display next to the title which is only available in the Metadata table.
This is as far as I got but obviously the issue with my SELECT statement is that it'll return the average of all movies and display it for each record:
SELECT
(SELECT
AVG(rating)
FROM
`movies-dataset.movies_data.ratings`) AS rating_avg,
metadata.title,
metadata.budget,
metadata.revenue,
metadata.genres,
metadata.original_language,
metadata.release_date
FROM
`movies-dataset.movies_data.Movies_metadata` AS metadata
INNER JOIN `movies-dataset.movies_data.ratings` AS ratings
ON metadata.id = ratings.movieId
LIMIT 10
Here is an example of the result:
Result
I'm thinking I can potentially use a GROUP BY but when I try, I get an error
Appreciate the help!
The following should work:
SELECT movies_metadata.title, AVG(ratings.rating)
FROM movies_metadata
LEFT JOIN ratings ON movies_metadata.id = ratings.movieID
GROUP BY movies_metadata.title
You can swap movies_metadata.title by movies_metadata.id if not unique.
The LIMIT function and GROUP function might conflict with each other. Try getting the average rating as part of the inner join like this:
SELECT
ratings.averagerating,
metadata.title,
metadata.budget,
metadata.revenue,
metadata.genres,
metadata.original_language,
metadata.release_date
FROM `movies-dataset.movies_data.Movies_metadata` AS metadata
INNER JOIN (SELECT movieId, AVG(rating) averagerating FROM `movies-dataset.movies_data.ratings` GROUP by movieId) AS ratings
ON metadata.id = ratings.movieId
ORDER BY ratings.averagerating
LIMIT 5
Maybe try something like:
Select m.movieID, (r.rate_sum / r.num_rate) as avg_rating
From your_movies_table m
Left Join (select movie_id, sum(rating) as ‘rate_sum’, count(rating) as ‘num_rate’
From your_ratings_table
Group by movie_id) r
On m.movie_id = r.movie_id
I'm using a left join because I'm not sure if all movies have been rated at least once.

How to Display the name of singer who has the maximum number of songs

Hi I am beginner and i want to Show that singer name who has maximum number of songs in songs table but i failed to do this because subquery cannot return two values at a time. how can i solve this problem. Below code shows this error -> Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
here is my code ->
SELECT Singer_Name
FROM Singer
WHERE Singer_id IN(SELECT TOP 1 Singer.Singer_id,COUNT(SongTitle) TotalSounds
FROM Singer,Songs
WHERE Songs.Singer_id=Singer.Singer_id
GROUP BY Singer.Singer_id
ORDER BY TotalSounds DESC)
This should do the trick:
SELECT TOP 1 n.Singer_Name, count(*) as Song_Count
FROM Songs s
INNER JOIN Singer n on n.Singer_id = s.Singer_id
GROUP BY n.Singer_id, n.Singer_Name
ORDER BY count(*) DESC
I added n.Singer_id to the group by on the off-chance that two singers could have the same name.
I hope this helps.
You were close to a workable solution. The issue is you were doing the subquery in the where clause, trying to limit your results that way, where you could just return the full list of names and number of songs and just pick the top one after ordering by the count:
SELECT TOP 1 SingerName FROM (SELECT Singer.Singer_Name, count(1) as TotalSounds
FROM Singer
JOIN Songs
ON Songs.Singer_id=Singer.Singer_id
GROUP BY Singer.Singer_Name, Singer.Singer_id) ss
ORDER BY TotalSounds DESC
If you have a tie for first place, and want to return both names, you make it TOP 1 WITH TIES otherwise it will just grab the first one, arbitrarily breaking the tie by the order they appear in the table (likely by Singer_id)
You can use group by statement like this:
SELECT Singer_Name, count(SongTitle) c FROM Singer
join Song on Song.singer_id = Singer.singer_id
group by Singer_Name
ORDER BY c desc limit 1;

SQL inner join with count() condition, and relationnal algebra

I have these tables:
Movies (id, name)
Cast (idmovie, actor)
And I would like to count the number of actors for each movie and then only get movies with more than 10 actors. I have a query to count the number of actors for each movie, which goes like this:
SELECT idmovie, count(actor) FROM Cast GROUP BY idmovie HAVING count(actor) > 10;
Now, I wonder how to get that result and join it to the Movies table.
I tried:
SELECT name FROM Movies INNER JOIN (SELECT idmovie FROM Cast GROUP BY idmovie HAVING count(actor) >2) Cast ON Cast.idmovie = Movies.id;
But it doesn't work.
I also have to translate it to relational algebra.
π name (σ (count(σ id = idmovie))) Movies⨝Cast
Which is obviously wrong...
Any help?
Try this...
SELECT m.name, COUNT(c.actor) AS 'ActorsCount'
FROM Movies m INNER JOIN [Cast] c ON m.id = c.idmovie
GROUP BY m.name HAVING COUNT(c.actor) > 10;
The query looks correct to me except perhaps that you aliased the nested query with Cast which is also the name of a table. I'm not sure what effect that'd have but I'd expect it to confuse MySQL. Try the following:
SELECT name FROM Movies INNER JOIN
(SELECT idmovie FROM Cast GROUP BY idmovie HAVING count(actor) >2) CastCount
ON CastCount.idmovie = Movies.id;
I didn't try it, but I think that'll work

SQLite Max of Count problem

I have the following query:
SELECT M.movieId, COUNT (*) AS mcount
FROM Movies M, Rentals R
WHERE M.movieId = R.movieId
GROUP BY M.movieId
I have a Movies DB and a Rentals DB, the resulting table currently shows the movie ID and how many times it has been checked out but i just can't figure out how to incorporate a MAX call on the mcount. Every time I try to do it I get a syntax error.
I want to be able to find the movie(s) that have been checked out the most.
You could just sort by the count column and limit the result to the number you want
SELECT M.movieId, COUNT(*) AS mcount
FROM Movies M, Rentals R
WHERE M.movieId = R.movieId
GROUP BY M.movieId
ORDER BY 2 DESC
LIMIT 1
would give you the top one.

Help in a Join query

SELECT game_ratingstblx245v.game_id,avg( game_ratingstblx245v.rating )
as avg_rating,
count(DISTINCT game_ratingstblx245v.userid)
as count,
game_data.name,
game_data.id ,
avg(game_ratings.critic_rating),count(DISTINCT game_ratings.critic)
as cr_count
FROM game_data
LEFT JOIN game_ratingstblx245v ON game_ratingstblx245v.game_id = game_data.id
LEFT JOIN game_ratings ON game_ratings.game_id = game_data.id
WHERE game_data.release_date < NOW()
GROUP BY game_ratingstblx245v.game_id
ORDER BY game_data.release_date DESC,
game_data.name
I am currenty using this query to extract values from 3 tables
game_data - id(foreign key), name, release_date \games info
game_ratings - game_id(foreign key),critic , rating \critic rating
game_ratingstblx245v - game_id(foreign key), rating, userid \user rating
What I want to do with this query is select all id's from table game_data order by release_date descending, then check the avg rating from table game_ratings and game_ratingsblx245v corresponding to individual id's(if games have not been rated the result should return null from fields of the latter two tables)..Now the problem I am facing here is the result is not coming out as expected(some games which have not been rated are showing up while others are not), can you guys check my query and tell me where am i wrong if so...Thanks
You shouldn't use the game_ratingstblx245v.game_id column in your GROUP BY, since it could be NULL when there are no ratings for a given game id. Use game_data.id instead.
Here's how I would write the query:
SELECT g.id, g.name,
AVG( x.rating ) AS avg_user_rating,
COUNT( DISTINCT x.userid ) AS user_count,
AVG( r.critic_rating ) AS avg_critic_rating,
COUNT( DISTINCT r.critic ) AS critic_count
FROM game_data g
LEFT JOIN game_ratingstblx245v x ON (x.game_id = g.id)
LEFT JOIN game_ratings r ON (r.game_id = g.id)
WHERE g.release_date < NOW()
GROUP BY g.id
ORDER BY g.release_date DESC, g.name;
Note that although this query produces a Cartesian product between x and r, it doesn't affect the calculation of the average ratings. Just be aware in the future that if you were doing SUM() or COUNT(), the calculations could be exaggerated by an unintended Cartesian product.