This question already has answers here:
How to resolve this SQL query?
(2 answers)
Closed 1 year ago.
Question from an exercise that I am not able to solve. I do not have enough knowledge.
query = For all cases where the same reviewer rated the same movie twice and gave it a higher rating the second time, return the reviewer's name and the title of the movie
If I try this:
SELECT title, max (stars)
FROM Movie
JOIN Rating on Movie.mID = Rating.mID
I get only one movie, I want to be able to see all movies from table "Movie" and the highest rate in case they have more than one rate in table "Rating"
What I get from question I guess this query will solve your problem
SELECT
mov.`title`,
MAX(rat.`rating`)
FROM
rating rat
JOIN movie mov
ON rat.`movie_id` = mov.`id`
WHERE mov.`id` IN
(SELECT
r.`movie_id`
FROM
rating r
GROUP BY r.`movie_id`
HAVING COUNT(*) > 1)
GROUP BY mov.`id`
Movie Table
Rating Table
Result
Use LEFT OUTER JOIN, to bring all values of the 'Movie' table.
Add Group by Clause to get the Title record only one, ie The Max Stars
in case the stars value is null, handle the output.
MaxRating alias for the max value
The script eg.
SELECT Movie.title, max(IFNULL(Rating.stars,0)) MaxRating
FROM Movie
LEFT JOIN Rating
on Movie.mID = Rating.mID
group by Movie.title
Related
I have two tables movie with moive id, movie title, director of the movie, and rating with rating id, movie id, and rating.
The question is to select director's name together with the title(s) of the movie(s) they directed that received the highest rating among all of their movies, and the value of that rating.
I am trying to understand the following solution
select distinct director, title, stars
from (movie join rating using (mid)) m
where stars in (select max(stars)
from rating join movie using (mid)
where m.director = director)
I am in particular confused with the last subquery
select max(stars)
from rating join movie using (mid)
where m.director = director
from all I know, '=' can only be followed by a fixed value, but here it seems to suggest 'looping' through all distinct directors. Which table is the latter director referring to? And how does the looping concept work in sql?
Although this code works to find the highest rated of all movies, it does not do so for each distinct director and it's not the simplest solution, which I will include below. However, the answers to your questions are:
1) The second director (from the where clause in the subquery) is referring to the table created in that subquery while the other m.director is using the m alias of the first table created in the main query.
2) This isn't really a loop here, in the traditional sense of the word. Basically what the above query is saying is: 'Give me the distinct director name, movie name, and rating from the table created by joining rating to movie, where the number of stars is the largest number of stars pulled from this subquery.' Loops for SQL server use the WHILE keyword but they are pretty rare in SQL since there are other functions (or clauses) that can fulfill the same purpose without the need for iteration.
The query posted in your comment only returns a single line with the data for the highest rated movie of all movies in the database not the highest rated movie for each director. The following is a simpler way of writing the query which gives the highest rating achieved for all movies for each director:
SELECT director, title, MAX(stars)
FROM movie
JOIN rating
ON movie.title = rating.movieID
GROUP BY director
Movie Table has the following columns:
Movie (Movie_ID, Movie_Title)
Customer Table has the following columns:
Customer (Cus_No, Cus_FName, Cus_LName)
Rental Table has the following columns:
Rental (Rental_ID, Cus_No, Movie_ID)
Now this is the question:
By using a single SQL Query (in MS Access), List the names of all movies and for all movies list the names of all customers who have hired it. If a movie has never been hired then list it anyway. Sort the final result by movie name and customer last name.
This is how I approached
SELECT Movie_Title, Cus_LName, Cus_FName
FROM Movie, Customer, Rental
WHERE Movie.Movie_ID = Rental.Movie_ID AND NOT (Movie.Movie_ID = Rental.Movie_ID)
AND Customer.Cus_No = Rental.Cus_No AND NOT (Customer.Cus_No = Rental.Cus_No)
ORDER BY Movie_Title, Cus_LName;
But, I am getting blank result.
How would the SQL Query look like in MS Access for this question?
The reason you get no results is that your conditions are contradictory:
You have:
Movie.Movie_ID = Rental.Movie_ID AND NOT (Movie.Movie_ID = Rental.Movie_ID)
... but these two conditions can never be true at the same time, yet you require them to be with AND.
What you are really looking for is outer joins.
SELECT Movie_Title, Cus_LName, Cus_FName
FROM (Movie
LEFT JOIN Rental ON Movie.Movie_ID = Rental.Movie_ID)
LEFT JOIN Customer ON Customer.Cus_No = Rental.Cus_No
ORDER BY Movie_Title, Cus_LName
This way a Movie record will still be listed even if the condition in the first ON clause has no match with a Rental record. In that case the SQL engine will fill up the missing values for the customer name with null. That is exactly what the LEFT JOIN is for. With WHERE you would lose out on such Movie records.
I am attempting to answer question #12 on sqlzoo.net
(http://sqlzoo.net/wiki/More_JOIN_operations). I couldn't figure out the answer on my own but I did manage to find the answer online.
12: Which were the busiest years for 'John Travolta', show the year and the number of movies he made each year for any year in which he made more than 2 movies.
Answer:
SELECT yr,COUNT(title) FROM
movie JOIN casting ON movie.id=movieid
JOIN actor ON actorid=actor.id
WHERE name='John Travolta'
GROUP BY yr
HAVING COUNT(title)=(SELECT MAX(c) FROM
(SELECT yr,COUNT(title) AS c FROM
movie JOIN casting ON movie.id=movieid
JOIN actor ON actorid=actor.id
WHERE name='John Travolta'
GROUP BY yr) AS t)
One of parts that I do not fully understand is the multiple joins:
FROM movie
JOIN casting ON movie.id=movieid
JOIN actor ON actorid=actor.id
Is Actor being joined only with Movie, or is actor being joined with Movie JOIN Casting?
I am trying to find a website that explains complex join statements as my attempted answer was far from correct (missing many sections). I think subselect statements with multiple complex join statements is a bit confusing at the moment. But, I could not find a good website that breaks the information up to help me form my own queries.
The other part I don't fully understand is this:
(SELECT yr,COUNT(title) AS c FROM
movie JOIN casting ON movie.id=movieid
JOIN actor ON actorid=actor.id
WHERE name='John Travolta'
GROUP BY yr) AS t)
3. What is the above code trying to find?
Ok, glad you are not afraid to ask, and I'll do my best to help clarify what is going on... Please excuse my re-formatting of the query to my mindset of writing queries. It better shows the relationships of where things are coming from (my perspective), and may help you too.
A few other things about my rewrite. I also like to use alias references to the tables so every column is qualified with the table (or alias) it originates from. It prevents ambiguity, especially for someone who does not know your table structures and relationships between tables. (m = alias to movie, c = alias for casting, a = alias for actor tables). For the sub query, and to keep alias confusion clear, I suffixed them with 2, such as m2, c2, a2.
SELECT
m.yr,
COUNT(m.title)
FROM
movie m
JOIN casting c
ON m.id = c.movieid
JOIN actor a
ON c.actorid = a.id
WHERE
a.name = 'John Travolta'
GROUP BY
m.yr
HAVING
COUNT(m.title) = ( SELECT MAX(t.movieCount)
FROM
( SELECT m2.yr,
COUNT(m2.title) AS movieCount
FROM
movie m2
JOIN casting c2
ON m2.id = c2.movieid
JOIN actor a2
ON c2.actorid = a2.id
WHERE
a2.name='John Travolta'
GROUP BY
m2.yr ) AS t
)
First, look at the outermost query (aliases m, c, a ) and the innermost query (aliases m2, c2, a2) are virtually identical.
The query has to run from the deepest query first... in this case the m2, c2, a2 query. Look at it and see what IT is going to deliver. If you ran that, you would get every year he had a movie and the number of movies... starting result from their sample data goes from 1976 all the way to 2010. So far, nothing complex unto itself (about 20 rows). Now, since each table may have an alias, each sub query (such as this MUST have an alias, so that is why the "as t". So, there is no true table, it is wrapping the entire query's result set and assigning THAT the alias of "t".
So now, go one level up in the query also wrapped in parens...
SELECT MAX(t.movieCount)
FROM (EntireSubquery as t)
Although abbreviated, this is what the engine is doing. Looking at the subquery result given an alias of "t" and finding the maximum "movieCount" value which is the count of movies that were done in a given year. In this case, the actual number is 3 and we are almost done.
Now, to the outermost query... again, this was virtually identical to the innermost query. The only difference is the HAVING clause. This is applied after all the grouping per year is performed. Then it is comparing ITs row result set count per year to the 3 value result of the SELECT MAX( t.movieCount )...
So, all the years that had only 1 or 2 movies are excluded from the result, and only the one year that had 3 movies are included.
Now, to clarify the JOINs. Each table should have a relationship with one or more tables (also known as linking tables, such as the cast table that has both a movie and actors/actresses. So, think of the join as how to I put the tables in order so that each one can touch a piece to the other until I have them all chained together. In this case
Movie -> Casting linked by the movie ID, then Casting -> actor by the actor ID, so that is how I do it visually hierarchically... I am starting FROM the Movie table, JOINing to the cast table based ON Movie ID = Cast Movie ID. Now, from the Casting table joined to the Actor table based on the common Actor ID field
FROM
movie m
JOIN casting c
ON m.id = c.movieid
JOIN actor a
ON c.actorid = a.id
Now, this is a simple relationship, but you COULD have one primary table with multiple child-level tables. You could join multiple tables based on the respective data. Very simple sample to clarify the point. You have a student table going to a school. A student has a degree major, an ethnicity, an address state (assuming an online school and students can be from any state). If you had lookup tables for degrees, ethnicity and states, you might come up with something like...
select
s.firstname,
s.lastname,
d.DegreeDescription,
e.ethnicityDescription,
st.stateName
from
students s
join degrees d
on s.degreemajor = d.degreeID
join ethnicity e
on s.ethnicityID = e.id
join states st
on s.homeState = st.stateID
Notice the hierarchical representation that each table is directly associated under that of the student. Not all tables need to be one deeper than the last.
So, there are many sites out there, such as the w3schools as offered by Mark, but learn to dissect small pieces at a time... what are the bare minimum tables to get from point-A to point-Z and draw the relationships. THEN, tare down based on requirement criteria you are looking for.
The correct answer would be:
SELECT yr, COUNT(title)
FROM movie m
JOIN casting c ON m.id=c.movieid JOIN actor a ON c.actorid=a.id
WHERE name='John Travolta'
GROUP BY yr
HAVING COUNT(title) > 2;
The answer you found (which seems to be a mistake on the sqlzoo site) is looking for any year that has a count equal to the year with the highest count.
I used table aliases in the query above to clear up how the tables are joined. Movie is joined to casting and casting is joined to actor.
The subquery that confuses you is listing each year and a count of movies for that year that star John Travolta. It's not needed if you're answering the question as written.
As for learning resources, make sure you have the basics down. Understand everything at http://w3schools.com/sql. Try searching for "sql joining multiple tables" in your favorite search engine when you're ready for more.
I have 3 tables :
Film.rating is the average of ratings for that film from the Rate table.
In SQL, to calculate film rating I would do:
SELECT AVG(Rate.rating)
FROM Rate, Film
WHERE Rate.uidFilm=Film.uidFilm;
I do not know how to write this in MS Access and where I should put this (or maybe another?) formula?
How do I 'connect' Film.rating with the calculation above?
In constructor for the Film table?
You need a GROUP BY in your query. Try this
SELECT Film.Title, AVG(Rate.rating)
FROM Rate
INNER JOIN Film ON Rate.uidFilm = Film.uidFilm
GROUP BY Film.Title;
This should give you the average ratings of all movies with their title.
Here's the dataset:
Movie (mID, title, year, director)
English: There is a movie with ID number mID, a title, a release year, and a director.
Reviewer (rID, name)
English: The reviewer with ID number rID has a certain name.
Rating (rID, mID, stars, ratingDate)
English: The reviewer rID gave the movie mID a number of stars rating (1-5) on a certain ratingDate.
Here's the question: find the titles of all movies that have no ratings.
My answer: (returns an empty set)
select m.title
from movie m
join rating r on m.mid = r.mid
where stars is null
Correct answer:
select title
from movie
left join rating using (mID)
where stars is null
I'm not sure what's wrong with my join? Thanks in advance!
Your query finds each movie record that does have a corresponding rating record — this is the meaning of movie JOIN rating — provided that said rating record has stars IS NULL.
The correct query finds each movie record that that either lacks a rating record or has a rating record with stars IS NULL.
The key difference is that your query will, as a first step, filter out any movie records without matching rating records (since these will fail the join), whereas the correct query uses a LEFT JOIN to prevent this filtering.
(Note that, even with a LEFT JOIN, this filtering can still happen if the WHERE clause is constructed poorly. For example, WHERE stars = 'X' would also filter out movie records without corresponding rating records, because only an existent rating record could satisfy the WHERE-clause. But with WHERE stars IS NULL, this problem does not arise, because NULL is the default value of stars when the join failed.)
you can use this query for which title has no stars,
"select title from movie left join rating on rating.mid = movie.mid where rating.rid is null"
or you can use
select title from movie where mid not in (select distinct mid from rating )