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

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

Related

Sql query returning empty table

I am trying to solve 2 queries
Find all the actors that made more movies with Yash Chopra than any other director
Select b.number,b.actor,b.director from (select MAX(a.count) as number,a.director,a.actor from
(select count(p.PID) as count ,p.PID as actor,md.PID as director from person as p left join m_cast
as
mc on trim(p.PID)=trim(mc.PID) inner join m_director as md on trim(md.MID)=trim(mc.MID) group by
md.PID ,p.PID) as a group by a.actor) as b where b.director=(select PID from person where
Name='Yash Chopra')
report for each year the percentage of movies in that year with only female actors, and the total number of movies made that year. For example, one answer will be: 1990 31.81 13522 meaning that in 1990 there were 13,522 movies, and 31.81% had only female actors. You do not need to round your answer.
SELECT female_count.year Year,
((female_count.Total_movies_with_only_female_leads)*100)/total_count.Total Percentage FROM ((SELECT
movie.year Year,count(*) Total_movies_with_only_female_leads FROM movie WHERE NOT EXISTS ( SELECT *
FROM M_Cast,person WHERE M_Cast.mid = movie.MID and M_Cast.PID = person.PID AND person.gender='Male'
) GROUP BY movie.year) female_count, (SELECT movie.year,count(*) as Total FROM movie group by
movie.year) total_count) WHERE female_count.year=total_count.year
Unfortunately for both the queries, I am getting empty table. Can someone help me in solving these 2 queries
I wrote it using CTEs so it is more readable.
First Question:
WITH HowManyMoviesPerActorDirector AS
(select mc.pid as actorpid
,pa.name as actorname
,md.pid as directorpid
,pd.name as producername
,count(mc.MID) as numberofmovies
from m_cast as mc
inner join m_director md on md.MID=mc.MID
inner join person pa ON mc.PID=pa.PID
inner join person pd ON md.PID=pd.PID
group by mc.pid as actorpid,md.pid
)
select h.acorname
,h.producername
,h.numberofmovies
from HowManyMoviesPerActorDirector h
WHERE h.numberofmovies = (select MAX(h2.numberofmovies)
from HowManyMoviesPerActorDirector h2
where h2actorpid=h.actorpid
group by h2actorpid)
AND h.producername='Yash Chopra'
The second one:
WITH MoviesIncludingGendeflag AS
( select m.mid
,m.year
,sum(case when p.gender='female' then 0 else 1 end) as genderflag
from movie m
inner join mc_cast mc on mc.mid=m.mid
inner join person p on p.pid=mc.pid
group by m.mid,m.year
) FemaleOnlyMovies AS
( select m.year,count(m.id) as Total
from MoviesIncludingGendeflag m
where generflag=0
group by m.year
), TotalMovies AS
(
select m.year,count(m.id) as Total
from movie m
group by m.year
)
select TM.year,TM.Total,(COALESCE(FOM.Total,0)*100.0/TM.Total) as percentage
from TotalMovies TM
left join FemaleOnlyMovies FOM ON FOM.year=TM.year

Shorten a query

I have to write a query that would calculate number of tickets purchased consisting only of movie genre of that type. At the end, I have to return movie genre and number of tickets bought for that genre. I have written a query but I was wondering if it can be made shorter and more compact?
Following is the database scheme:
movies(movieId, movieGenre, moviePrice)
tickets(ticketId, ticketDate, customerId)
details(ticketId, movieId, numOfTickets)
Here is my query:
select m.genre, count(*)
from(select t.ticketId, m.genre
from(select d.ticketId
from(select m.genre, t.ticketId
from tickets t join details d on t.ticketId =
d.ticketId join movies m on d.movieId = m.movieId
group by m.genre, t.ticketId) d
group by d.ticketId
having count(*) = 1) as t join details d on t.ticketId =
d.ticketId join movies m on d.movieId = m.movieId
group by t.ticketId, m.genre) m
group by m.genre;
This runs on a database so I am only able to post sample output:
comedy 29821
action 27857
rom-com 19663
I see no reason to use the table tickets, because the results do not filter or aggregate by ticketDate or customerID. Thus, a shorter sql is
SELECT m.moviegenre,
Sum(d.numoftickets) as SumNum
FROM details d
LEFT JOIN movies m
ON d.movieid = m.movieid
GROUP BY m.moviegenre
HAVING SumNum > 0
ORDER BY m.moviegenre
added 3/28 am
I am not sure what is meant by Duplicates?? In table = details(ticketId, movieId, numOfTickets) ??
I would expect that ticketId is unique, so what would explain duplicates?
Is the same ticketId being printed twice, repeatedly??
Determine what number of ticketId are duplicates--
SELECT ticketId, count(*) as cnt
FROM details d
GROUP By ticketId
HAVING count(*) > 1
Determine what number of "details" rows are duplicates--
SELECT ticketId, movieId, numOfTickets, count(*) as cnt
FROM details d
GROUP By ticketId, movieId, numOfTickets
HAVING count(*) > 1
Then again, it may be that table = movies(movieId, movieGenre, moviePrice) is the one with duplicates??
Determine what number of movieId are duplicates--
SELECT movieId, count(*) as cnt
FROM movies m
GROUP BY movieId
HAVING count(*) > 1
Remove duplicates from details--
SELECT m.moviegenre,
Sum(d.numoftickets) as SumNum
FROM
(Select Distinct * From details) d
LEFT JOIN movies m
ON d.movieid = m.movieid
GROUP BY m.moviegenre
ORDER BY m.moviegenre

Including SUM on SQL Inner Join query

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.

Get all values from biggest group

I have a table of students and a table of books that they borrowed. I need to find a student who borrowed the most books and show titles of these books.
Currently I have a list of students and number of books that each student borrowed, sorted descending. I can get the student who borrowed the most by using Top 1.
SELECT TOP 1 Students.Name, Students.LastName, Count(Books.Title) AS BorrowedBooksCount
FROM (Meldunek INNER JOIN Students ON Meldunek.pesel = Students.pesel)
INNER JOIN Books
ON Students.pesel = Books.pesel
GROUP BY Students.Name, Students.LastName
ORDER BY Count(Books.Title) DESC;
How to show names of books of a student who borrowed the most books?
To get the student who borrowed the most books:
select top 1 m.pesel
from Meldunek as m
group by m.pesel
order by count(*) desc;
You can use this in a where clause for filtering. But you should take into account that multiple students might have the same value. So, use in rather than =:
where s.pesel in (select top 1 m.pesel
from Meldunek as m
group by m.pesel
order by count(*) desc
);
This logic can be inserted into your query, so you return only the top borrowing students.
The complete query looks like:
select s.Name, s.LastName, b.Title
from (Meldunek as m inner join
Students s
on m.pesel = s.pesel
) inner join
Books as b
on s.pesel = b.pesel
where s.pesel in (select top 1 m2.pesel
from Meldunek as m2
group by m2.pesel
order by count(*) desc
);

MAX(COUNT(*)) for each ID in a SQL query

I'm needing some help with a SQL query using PostgreSQL 9.4.
I need the most rented movies on each local, this is the data I'm asked to select
movie title
year
local id
number of rents
Tables:
rental(idMovie, idLocal, idClient)
movies(idMovie, title, description, year)
This is what I have done, but is not what i am asked to do.
SELECT m.tile, m.year, r.idLocal, COUNT(*) AS cont
FROM rental r, movies m
WHERE m.idMovie=r.idMovie
GROUP BY r.idLocal, m.title, m.year
ORDER BY COUNT(*) DESC;
If I understand your question correctly what you want is to show the most rented out movie(s) for every location.
If that is the case then you could use a window function like rank() which will assign a ranking number to all movies based on the number of rentals for each location. The where clause then filters out the highest ranking movies (there can of course be more than one that shares the top spot).
select m.title, m.year, r.idLocal, r.rents
from movies m
join (
select
idMovie,
idlocal,
count(idmovie) rents,
rank() over (
partition by idlocal
order by count(idmovie) desc
) rn
from rental
group by idMovie, idLocal
) r on m.idMovie = r.idMovie
where rn = 1
order by idlocal;
Sample SQL Fiddle
Try this...
SELECT r.idLocal, m.title, m.year, count(r.idMovie) as count_movie
FROM rental r, movies m
WHERE m.idMovie=r.idMovie
GROUP BY r.idLocal, m.title, m.year
ORDER BY count_movie DESC;
Or
SELECT r.idLocal, m.title, m.year, count(r.idMovie) as count_movie
FROM rental r, movies m
WHERE m.idMovie=r.idMovie
GROUP BY r.idLocal, m.title, m.year
ORDER BY count(r.title) DESC;