Including SUM on SQL Inner Join query - sql

I have two tables, movies and reservations. I'm trying to figure out how to get my query to return only unique movie ids/titles and sum the total number of tickets listed in a table with multiple entries per movie.
Below is what I'm trying, with no luck. What am I missing here?
SELECT movies.id AS id, movies.title AS title, SUM(reservations.number_of_tickets) AS sold_tickets
FROM reservations
INNER JOIN movies ON reservations.movie_id = movies.id
ORDER BY sold_tickets DESC, id
When I run the query without trying SUM, I almost get what I want, except the query has multiple rows for the same movies:
SELECT movies.id AS id, movies.title AS title, reservations.number_of_tickets AS sold_tickets
FROM reservations
INNER JOIN movies ON reservations.movie_id = movies.id
ORDER BY sold_tickets DESC, id
Thanks for your help!

You are missing a GROUP BY:
SELECT m.id, m.title, SUM(r.number_of_tickets) AS sold_tickets
FROM movies m INNER JOIN
reservations r
ON r.movie_id = m.id
GROUP BY m.id, m.title
ORDER BY sold_tickets DESC, id;
Notes:
Learn to use subqueries.
There is no need to rename a column to the same name. So movies.id is already called id in the result set.
I swapped the order of the joins. I do so you can turn the INNER JOIN to a LEFT JOIN if you want movies with no reservations.

Related

Asking a condition based on two cases in the same column. sqlite3

I am trying to insert into a new table all the names of the movies where helena bonhab carter and johnny depp starred in. I am selecting information firstfrom a table called movies which has a title and an id. and then from a table called stars which has a movie_id and a person_id. and lastly I am selecting from a table called people which has a id and name columns. I think my problem is in the union line but i don't know why.
CREATE TABLE jh( title TEXT)
INSERT INTO jh(title)
SELECT movies.title
FROM movies
WHERE movies.id in ( SELECT stars.movie_id FROM stars WHERE stars.person_id in(SELECT
people.id FROM people WHERE people.name = ' Johnny Depp' UNION SELECT people.id FROM people
WHERE people.name = 'Helena Bonham Carter'))
You can join the tables, filter for the actors you want, group by movie and set the condition the HAVING clause:
SELECT m.title
FROM movies m
INNER JOIN stars s ON s.movie_id = m.id
INNER JOIN people p ON p.id = s.person_id
WHERE p.name IN ('Johnny Depp', 'Helena Bonham Carter')
GROUP BY m.id, m.title
HAVING COUNT(*) = 2 -- the number of the actors
I really suggest you don't do query like that. for example, you could select all names in one single WHERE condition. And be ready to use JOIN if you have several tables need to be connected.
SELECT M.Title
FROM Movies M INNER JOIN Stars S on M.id = S.Movie_Id
INNER JOIN People P on S.PersonID = P.PersonID
WHERE P.Name in ('Johnny Depp','Helena Bonham Carter')

sql: get a single-column table, order by column from another table

I have interconnected tables.
movies (main, parent) : id | title | year
people (child) : people_id | name | birthyear
ratings (child) : movie_id | rating | votes
stars (child) : movie_id | person_id
I need to make a query ang get a sinle column output from tables "movies-people-stars" and order that by column from the table "rating" without joining column "rating" to my output.
My code:
SELECT title from movies
where id in (select movie_id from stars
where person_id in(select id from people where name = "Chadwick Boseman"))LIMIT 5;
It returns all titles of movies where Chadwick Boseman plays. I need to order them by rating. How to do it?
Although this would never be done without a join, since it is homework, you can use a correlated subquery for the table ratings in the ORDER BY clause:
select m.title
from movies m
inner join stars s on s.movie_id = m.id
inner join people p on p.people_id = s.person_id
where p.name = 'Chadwick Boseman'
order by (select r.rating from ratings r where r.movie_id = m.id) desc
limit 5
You could also use your query and add the ORDER BY clause:
select m.title
from movies m
where m.id in (
select movie_id
from stars
where person_id in(
select id
from people
where name = 'Chadwick Boseman'
)
)
order by (select r.rating from ratings r where r.movie_id = m.id) desc
limit 5;
You need to include the column in the select list to order by that column. Order by sorts your output in the order of the column you specify. Also, why can't you use JOINs for your query like below.
SELECT m.title,d.rating
FROM movies m
JOIN stars s ON s.movie_id = m.id
JOIN people p ON p.id = s.person_id
JOIN tbl d ON d.xx = z.yy ----- JOIN the table d here and use it in select . replace z,xx and yy with actual table name and columns.
WHERE p.name = "Chadwick Boseman"
ORDER BY d.rating
LIMIT 5
updated* - It might work but not able to test as I don't have access to actual data and tables.
SELECT m.title
FROM movies m
JOIN stars s ON s.movie_id = m.id
JOIN people p ON p.id = s.person_id
WHERE p.name = 'Chadwick Boseman'
AND m.id in (SELECT top 5 movie_id
FROM ratings r
WHERE r.movie_id = m.id
ORDER BY ratings desc)

Need advice with a Query to list Top 5 rated games

Hi i am helping my friend create a website that shows ratings for games.
My table and columns are:
Games
game_id
title
genre
Ratings
user_id
game_id
rating
timestamp
Users
user_id
gender
age
Occupation
zip code
I would need help creating a SQL query that lists:
Top 5 highest rated games per user gender
Top 5 highest rated games per user age group
Top 5 highest rated games per occupation
I have tried looking at https://www.w3schools.com/sql/sql_groupby.asp but i am not good with SQL and could use some advice
I would recommend the use of INNER JOINS to pull the data together:
SELECT g.title, g.genre, r.rating, u.gender
FROM rating r
INNER JOIN u.user_id on r.user_id = u.user_id
INNER JOIN g.game_id on r.game_id = g.game_id
This data can then be sorted by using an ORDER BY clause to allow for the rating to be sorted accordingly:
SELECT g.title, g.genre, r.rating, u.gender
FROM rating r
INNER JOIN u.user_id on r.user_id = u.user_id
INNER JOIN g.game_id on r.game_id = g.game_id
ORDER BY r.rating DESC;
In order to only return the top number of results, use the LIMIT number clause.
A complete example of this can be seen below:
SELECT g.title, g.genre, r.rating, u.gender
FROM rating r
INNER JOIN u.user_id on r.user_id = u.user_id
INNER JOIN g.game_id on r.game_id = g.game_id
ORDER BY r.rating DESC
LIMIT 5;
This example tailors to the first SQL Query requirement that you listed - the other two queries can be achieved by following the same structure.
EDIT :
After further understanding of the OP's original post, the complete example query above is adapted below. Since the requirement is to return the top 5 games based on their averaged ratings from users - the use of the clause AVG() must be used to obtain the averages of game ratings.
Whilst the use of the GROUP BY clause allows for each unique game_id to have it's average value calculated for it. Example of these clauses in use:
SELECT g.title, g.genre, AVG(r.rating), u.gender
FROM rating r
INNER JOIN u.user_id on r.user_id = u.user_id
INNER JOIN g.game_id on r.game_id = g.game_id
GROUP BY g.game_id
ORDER BY AVG(r.rating) DESC
LIMIT 5;

Count number of ID in a table and select one or all top values(max) in POSTGRESQL

I have a table(film_actor) that holds a relationship between two other tables, film and actor.
I want to count the number of occurences of actor.id in the table film_actor and then select the top value or values, but cant seem to get it to work.
My query so far is as below which gives me a nice list of all actors and the number of movies they have been in. What I cant seem to do is select the highest value or values. I know I can just limit the results to 1, or top 1, but I need it to be dynamic in case the list has 2 or more actors with the same number of movies.
SELECT actor.first_name, actor.last_name, COUNT(actor.actor_id) AS film_number
FROM actor
INNER JOIN film_actor ON actor.actor_id = film_actor.actor_id
GROUP BY actor.actor_id, actor.first_name, actor.last_name
ORDER BY film_number DESC
I havent been able to nest MAX() into this, but Im thinking this is what I need. All tips are welcome!
The best way to write this type of query is to use rank() or dense_rank():
SELECT fa.*
FROM (SELECT a.first_name, a.last_name, COUNT(a.actor_id) AS film_number,
RANK() OVER (ORDER BY COUNT(a.actor_id) DESC) as seqnum
FROM actor a INNER JOIN
film_actor fa
ON a.actor_id = fa.actor_id
GROUP BY a.actor_id, a.first_name, a.last_name
) fa
WHERE seqnum = 1;
I ended up solving this by using HAVING and ALL, see below:
SELECT
actor.first_name, actor.last_name, COUNT(film_actor.actor_id) as Antalfilmer
FROM
film_actor
INNER JOIN actor ON film_actor.actor_id = actor.actor_id
GROUP BY actor.first_name, actor.last_name, actor.actor_id
HAVING COUNT(film_actor.actor_id) >= ALL (SELECT COUNT(film_actor.actor_id) FROM film_actor JOIN actor ON actor.actor_id = film_actor.actor_id GROUP BY actor.first_name, actor.last_name, actor.actor_id)

I don't understand this SQL Server MIN() resultset

I have this SQL Server query which I wrote to find the Movie title that has the least amount of records in the RENTAL table.
When run, it returns a resultset that is identical to the resultset I get from executing the sub-query by itself.
In other words, rather returning the single movie with the minimum RentalCount, it returns all movie titles and their corresponding RentalCount.
SELECT B.Title, MIN(B.RentalCount) AS RentalCount
FROM (
SELECT Movie.Title, Count(*) AS RentalCount
FROM Rental
JOIN Dvd ON Rental.RentalID=Dvd.DvdID
JOIN Movie ON Dvd.Movieid=movie.MovieID
GROUP BY Movie.Title
) B
GROUP BY B.Title
The result is correct. Your subquery returns the total count for each title on the rental table. And the result will be the same on the outer query because you have grouped them by their title also.
follow-up question: what result do you want to achieved?
find the Movie title that has the least amount of records in the RENTAL table
SELECT Movie.Title, Count(*) AS RentalCount
FROM Rental
JOIN Dvd ON Rental.RentalID=Dvd.DvdID
JOIN Movie ON Dvd.Movieid=movie.MovieID
GROUP BY Movie.Title
HAVING Count(*) =
(
SELECT MIN(t_count)
FROM
(
SELECT Count(*) t_count
FROM Rental
GROUP BY Title
) a
)
UPDATE 1
Thanks to Martin Smith for introducing me TOP....WITH TIES
SELECT TOP 1 WITH TIES Movie.Title, Count(*) AS RentalCount
FROM Rental
JOIN Dvd ON Rental.RentalID=Dvd.DvdID
JOIN Movie ON Dvd.Movieid=movie.MovieID
GROUP BY Movie.Title
ORDER BY RentalCount DESC
SQLFiddle Demo
You could have done this without a subquery
SELECT TOP 1 Movie.Title, Count(*) AS RentalCount
FROM Rental
JOIN Dvd ON Rental.RentalID=Dvd.DvdID
JOIN Movie ON Dvd.Movieid=movie.MovieID
GROUP BY Movie.Title
ORDER BY Count(*)
if you are looking for a specfic movie title then do like this:
SELECT Movie.Title, Count(*) AS RentalCount
FROM Rental
JOIN Dvd ON Rental.RentalID=Dvd.DvdID
JOIN Movie ON Dvd.Movieid=movie.MovieID
where Movie.Title='xyz'
GROUP BY Movie.Title