SQL get sum of multiple averages - sql

I have a table with Songs, users and users rating of the song.
ratings.*
userID
songID
rating
95
1
8
12
1
6
95
1
8
13
1
6
81
2
3
42
2
1
51
3
6
22
3
6
I also have a table thet matches songID's and artists.
songs.*
songID
artist
1
Michal Jackson
2
Queen
What I need is to get the average rating of each song, and then take the sum to find a total rating for the artist.
So here, ill try to show with the input, Michel Jackson.
SELECT SUM( AVG(ratings.rating WHERE songID=1) + AVG(ratings.rating WHERE songID=3) )
Wanted output
Input, artist
Output, total rating
"Michal Jackson"
13
"Queen"
2
Every answer is really appreciated, thank you.

You could use a derived table (using a subquery as a table):
SELECT
songID
, SUM(average_rating) AS total_rating
FROM (
SELECT
songID
, artist
, AVG(rating) AS average_rating
FROM songs
GROUP BY songID
) AS song_ratings
GROUP BY artist

Related

create pivot table using sql

I have a database called player.db
These database has two tables.
The tables called person and the other is called match.
person table is
Player_ID
Player
Country
1
Lionel Messi
Argentina
2
Luis Suarez
Uruguay
3
Neymar
Brazil
match table is
Match _ID
Game
Player_ID
Date
Season
1
Uruguay-Paraguay
2
5/3/2019
1
2
Uruguay-Chile
2
19/3/2019
1
3
Argentina-Chile
1
22/3/2019
1
4
Brazil-Guyana
3
3/4/2019
1
5
Brazil-USA
3
1/6/2020
2
6
Brazil-Belize
3
3/7/2020
2
7
Brazil-Suriname
3
5/7/2020
2
8
Argentina-USA
1
8/8/2020
2
9
Argentina-Canada
1
3/3/2021
3
10
Argentina-Grenada
1
8/3/2021
3
11
Uruguay-Suriname
2
7/4/2021
3
12
Uruguay-Mexico
2
2/2/2022
4
13
Uruguay-Jamaica
2
4/2/2022
4
14
Brazil-Ecuador
3
5/2/2022
4
My pivot table should look like these:
Season
Player
1
Luis Suarez
2
Neymar
3
Lionel Messi
4
Luis Suarez
I want a sql code which create a pivot table which shows which player played most with topscore in which season year. For example Luis Suarez occured most in season 1.
I started coding in sql, but got not the desired solution
SELECT Player_ID, COUNT(*)FROM match GROUP BY Player_ID HAVING COUNT(*) max
The problem is I got an error and it doesn't create a pivot table which show which player played most in which season.
Join the tables, group by season and player to get the number of matches for each player and use FIRST_VALUE() window function to pick the top player of each season:
SELECT DISTINCT m.Season,
FIRST_VALUE(p.Player) OVER (PARTITION BY m.Season ORDER BY COUNT(*) DESC) Player
FROM match m INNER JOIN person p
ON p.Player_ID = m.Player_ID
GROUP BY m.Season, m.Player_ID;
See the demo.
Your clause HAVING count(*) max may cause the error.
The solution may depend on the relational data base you use. Here is a solution with postgresql :
SELECT DISTINCT ON (Season)
m.season, p.player, count(*) AS count
FROM match AS m
INNER JOIN player AS p ON p.player_ID = m.Player_ID
GROUP BY m.Season, p.Player_ID, p.player
ORDER BY m.Season ASC, count DESC
see dbfiddle

How to write SQL subqueries with count?

I'm using mysql. I want to count the minimum, maximum, and average number of different tags per movie from one table.
Exclude the duplicate:
same tag given by the same user to the same movie
same tag given by different users to the same movie
Example: table 'tags'
userId
movieId
tag
1
1
crime
1
2
dark
1
2
dark
2
2
greed
2
2
dark
3
3
music
3
3
dance
3
3
quirky
4
3
dance
4
3
quirky
Expect result:
movieId
Min_Tag
Max_Tag
Avg_Tag
1
1
1
1
2
1
2
0.66...
3
1
2
0.6
I try to write query like below, but it shows an error.
SELECT
DISTINCT movieId,
MIN(COUNT(DISTINCT tag) AS Min_Tag,
MAX(COUNT(DISTINCT tag) AS Max_Tag,
AVG(COUNT(DISTINCT tag) AS Avg_Tag,
FROM (
SELECT userId,movieId,tag
FROM tags
GROUP BY userId, movieId, tag
) AS non_dup
GROUP BY movieId;
You have to rewrite your query
First you need the count per tag and movie
and fromm that you can calculate min max and avg
SELECT
movieId,
MIN(count_tag) AS Min_Tag,
MAX(count_tag) AS Max_Tag,
AVG(count_tag) AS Avg_Tag
FROM
(SELECT movieId,tag, count(*) count_tag
FROM tags
GROUP BY movieId, tag) non_dup
GROUP BY movieId
movieId
Min_Tag
Max_Tag
Avg_Tag
1
1
1
1.0000
2
1
3
2.0000
3
1
2
1.6667
fiddle

Select columns from a table and count a value from another table

I have the following tables:
table_user
id
name
1
Arnold
2
Wesley
3
Abel
4
Harry
5
Cristiano
table_post
fk_user is from user who created the post
id
fk_user
title
description
1
2
Movie
I like horror movies
2
4
Music
Music is essential to my days
3
4
Soccer
The World Cup is coming!
table_post_like
fk_user is from user who liked the post
fk_post
fk_user
1
1
1
3
1
4
1
5
2
2
3
3
3
1
I need to select all posts liked by user Arnold (id 1) with all columns from tb_post and number of likes. The result would be something like that:
id
fk_user
title
description
likes
1
2
Movie
I like horror movies
4
3
4
Soccer
The World Cup is coming!
2
I tried this but the number of likes is not correct
SELECT TP.*, COUNT(TPL.fk_post) AS likes
FROM table_post AS TP
RIGHT JOIN table_post_like AS TPL
ON TP.id = TPL.fk_post
WHERE TPL.fk_user = 1
GROUP BY TP.id
Do this
SELECT table_post.*, t.occurence FROM table_post
JOIN
(SELECT fk_post, COUNT(fk_user) as occurence FROM table_post_like WHERE fk_post IN(SELECT fk_post FROM table_post_like WHERE fk_user = 1)
GROUP BY fk_post) as t ON t.fk_post = table_post.id
Query above returns the value as expected
id
fk_user
title
description
likes
1
2
Movie
I like horror movies
4
3
4
Soccer
The World Cup is coming!
2
Check db fiddle here

Delete Group of Records based on Group Statistic

I have the following two example tables
Teams
Team ID
Team Name
1
Bears
2
Tigers
3
Lions
4
Sharks
Players
Player ID
Name
Team ID
Playtime
1
John
1
5
2
Adam
1
4
3
Smith
1
5
4
Michelle
2
5
5
Stephanie
2
10
6
David
2
10
7
Courtney
2
2
8
Frank
2
7
9
Teresa
2
1
10
Michael
3
3
11
May
4
1
12
Daniel
4
1
13
Lisa
4
4
I need a select statement with the following criteria
Select all teams with less than 4 players
Figure out the total playtime for all players on those teams and sort the resulting table based on this in descending order
Based on the example given, I would want a table that looks like this:
Teams
Team Name
Num Players
Total Playtime
Bears
3
14
Sharks
3
6
Lions
1
3
Finally, I want to cut all even rows from the previous table, so the final table would look like:
Team Name
Num Players
Total Playtime
Bears
3
14
Lions
1
3
You may try the following:
Query #1
SELECT
t."Team Name",
COUNT(p."Player ID") as "Num Players",
SUM(p."Playtime") as "Total Playtime"
FROM
teams t
LEFT JOIN
players p ON t."Team ID"=p."Team ID"
GROUP BY
t."Team Name"
HAVING
COUNT(p."Player ID") < 4
ORDER BY
SUM(p."Playtime") DESC;
Team Name
Num Players
Total Playtime
Bears
3
14
Sharks
3
6
Lions
1
3
Query #2
SELECT
t1."Team Name",
t1."Num Players",
t1."Total Playtime"
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY SUM(p."Playtime") DESC) as rn,
t."Team Name",
COUNT(p."Player ID") as "Num Players",
SUM(p."Playtime") as "Total Playtime"
FROM
teams t
LEFT JOIN
players p ON t."Team ID"=p."Team ID"
GROUP BY
t."Team Name"
HAVING
COUNT(p."Player ID") < 4
) t1
WHERE MOD(rn,2)=1
ORDER BY rn;
Team Name
Num Players
Total Playtime
Bears
3
14
Lions
1
3
View on DB Fiddle
Let me know if this works for you.

Combine 3 tables and get name according to average scores

I have a question about sql.
I have 3 tables.
Table 1 is student. It has student id and student name
Table 2 is school. It has school id and school name
Table 3 is scores. It has school id, student id and scores
I am trying to write a query where you select school name, if average of the scores for that school is above 70.
The SCORES table looks like this. I know, same student goes to 2 schools sounds stupid. Ignore that logic
SCORES
STUDENT_ID SCHOOL_ID SCORE
1 4 90
1 7 67
3 5 87
3 4 78
5 3 56
6 4 95
You can aggregate and filter with a having clause. If you just want the id of the school, you can get the result you want by looking at the scores table only:
select school_id, avg(scores) avg_score
from scores
group by school_id
having avg(scores) > 70
If you want the shool name, then use a join:
select sh.school_id, sh.school_name, avg(sc.scores) avg_score
from schools sh
inner join scores sc on sc.school_id = sh.school_id
group by sh.school_id, sh.school_name
having avg(sc.scores) > 70