Why is the answer to this question incorrect?
Database
movie (id(PK), title, yr, director(FK), budget, gross)
actor (id(PK), name )
casting (movieid(PK, FK), actorid(PK, FK), ord)
Question: List the films in which 'Harrison Ford' has appeared (original link here)
My answer:
select title
from movie
were id IN
(
select movieid as id
from casting
where actorid IN
(
select id as actorid
from actor
where name = 'Harrison Ford'
)
) X
After correcting were -> where and removing the trailing X the syntax and result where correct.
select title
from movie
where id IN
(
select movieid as id
from casting
where actorid IN
(
select id as actorid
from actor
where name = 'Harrison Ford'
)
)
Error message indicated it was using MariaDB
select title from movie inner join casting on (movie.id = casting.movieid)
inner join actor on (casting.actorid = actor.id)
where actor.name = 'Harrison Ford'
Please use the above SQL code for this question on SQL Zoo; it is in the exercise related to "More Joins". Hence you should be using Joins to solve it
My solution using CTE and JOIN:
-- find the movieid in which Harrison Ford played
WITH t AS (
SELECT DISTINCT movieid
FROM actor
JOIN casting ON actor.id = casting.actorid
WHERE name = 'Harrison Ford'
)
-- Get the movie title using a simple inner join
SELECT title
FROM movie
JOIN t ON movie.id = t.movieid
Related
I'm meant to use an implicit join to get all the movies with angelina jolie as director or were she stars here's what I have so far
SELECT DISTINCT title, relYear
FROM actor,movie
WHERE director ='Angelina Jolie' OR aID in (SELECT aID
FROM actor
WHERE fName='Angelina' and surname='Jolie'
Here are the relevant tables
movie(id, title, relYear, category, runTime, director,
studioName, description, rating)
actor(aID, fName, surname, gender)
stars(movieID, actorID)
movGenre(movieID, genre)
This returns all of the movies , I think that's because of aID in (SELECT aID
I don't know how to do this without using explicit join on three tables is the subquery even the most efficient approach ? Thanks
This is what I would do on MSSQL. Think it should work on MySql.
Select title, relYear FROM movie WHERE director = 'Angelina Jolie' OR id IN
(SELECT movieId FROM stars inner join actor ON stars.actorId = actor.aID WHERE
actor.fName = 'Angelina' AND surname = 'Jolie')
SELECT DISTINCT actor_id
FROM
(SELECT DISTINCT actor_id
FROM cast
WHERE NOT movie_id in
(SELECT movie_id
FROM cast
INNER JOIN actors
ON actors.ID = cast.actor_id
WHERE full_name = 'Kevin Bacon')) as A
WHERE movie_id in
(SELECT movie_id
FROM cast
WHERE actor_id in
(SELECT DISTINCT actor_id
FROM cast
WHERE movie_id in
(SELECT movie_id
FROM cast
INNER JOIN actors
ON actors.ID = cast.actor_id
WHERE full_name = 'Kevin Bacon')))
AND actor_id <> (SELECT id from actors
where full_name = "Kevin Bacon")
;
I keep getting this error of Unknown column 'movie_id' in 'IN/ALL/ANY subquery'; which i do not understand, as the blocks of this code taken separately work just fine.
What am I missing here?
Thks!
I see and error on this simplified example of your query:
SELECT DISTINCT actor_id
FROM ( SELECT DISTINCT actor_id FROM ...) as A
WHERE movie_id in (...);
On the WHERE clause you are referencing "movie_id" from "A" table, but in the inner query "( SELECT DISTINCT actor_id FROM ...)" this column is not selected.
Also, there are so much anidated queries, i'm sure this can be simplified if you give an example "with words" of what you want to get.
Response to the commented goal
I did not found an easy answer for your goal, but i will go this way:
First, i will create a view with actors relationship based on the movies they acted...
CREATE VIEW vw_relations AS (
SELECT
c1.actor_id AS actor1_id, a1.full_name AS actor1_fullname,
c1.movie_id, m.title AS movie_title,
c2.actor_id AS actor2_id, a2.full_name AS actor2_fullname
FROM
cast AS c1
INNER JOIN
cast AS c2 ON c2.movie_id = c1.movie_id AND c2.actor_id != c1.actor_id
INNER JOIN
movies AS m ON m.id = c1.movie_id
INNER JOIN
actors AS a1 ON a1.id = c1.actor_id
INNER JOIN
actors AS a2 ON a2.id = c2.actor_id
);
Now, if actor NAME1 participated on the same movie that actor NAME2 there will be rows with next values on the previous view:
(id_name1, name1, movie_id, movie_title, id_name2, name2)
(id_name2, name2, movie_id, movie_title, id_name1, name1)
In other words, the relation will appear twice, but this simplify next queries...
Now, based on your definition, the 1º degrees of closeness for actor "Kevin Bacon" (actors that worked with him) can be obtained like this:
CREATE VIEW vw_1_degree_to_kb AS (
SELECT
actor1_id, actor1_fullname
FROM
vw_relations
WHERE
actor2_fullname = "Kevin Bacon"
);
Now, for the 2º degrees of closeness for actor "Kevin Bacon" (actors that worked with actors that worked with him) i will do this (and save in a view too):
CREATE VIEW vw_2_degree_to_kb AS (
SELECT
actor1_id, actor1_fullname
FROM
vw_relations
WHERE
actor2_id IN (SELECT actor1_id FROM vw_1_degree_to_kb)
AND
actor1_id NOT IN (SELECT actor1_id FROM vw_1_degree_to_kb)
AND
actor1_fullname != "Kevin Bacon"
);
In others words, this view contains actors that worked with the 1º degree of closeness actors of "Kevin Bacon", but that not already belong to that set.
Even more, the 3º degrees of closeness will be like this:
CREATE VIEW vw_3_degree_to_kb AS (
SELECT
actor1_id, actor1_fullname
FROM
vw_relations
WHERE
actor2_id IN (SELECT actor1_id FROM vw_2_degree_to_kb)
AND
actor1_id NOT IN (SELECT actor1_id FROM vw_1_degree_to_kb)
AND
actor1_id NOT IN (SELECT actor1_id FROM vw_2_degree_to_kb)
AND
actor1_fullname != "Kevin Bacon"
);
I have the following tables:
Movie ( mID, title, year, director )
Reviewer ( rID, name )
Rating ( rID, mID, stars, ratingDate )
What i want to do is get the directors name along with the movies name which he has directed and got the highest rating.
For example, if Steven Spielberg has directed two movies (namely A and B) which have got 3 stars and 5 stars rating respectively, then the query must show Steven Spielberg and B (movie with the highest rating).
PS: I only need help with the approach. Hope I made myself clear. Please ask if any more info or explanation needed.
Why dont you try this,
SELECT TITLE,DIRECTOR FROM MOVIE,
(SELECT MAX(STARS),mID FROM RATING GROUP BY mID) R
WHERE MOVIE.mID=R.mID
Set up a subselect to get the director and the highest rating:-
SELECT director, MAX(stars)
FROM Movie
INNER JOIN Rating
ON Movie.mID = Rating.mID
INNER JOIN
(
SELECT director, MAX(stars) AS MaxRating
FROM Movie
INNER JOIN Rating
ON Movie.mID = Rating.mID
GROUP BY director
) Sub1
ON Movie.directort = Sub1.director
AND Rating.stars = Sub1.MaxRating
However I presume you will need more details. You do not appear to use the reviewer table at the moment, and I presume that one movie could have had several different reviewers who could have given different ratings. If so you would want to use the above as a subselect to join back against the rating table (macthign on the title and stars), and from that to the reviewer table.
Here you go
SELECT q.* FROM (SELECT m.*,MAX(r.`stars`) AS maxrating FROM `movie` m
INNER JOIN `rating` r ON (m.`mID` = r.`mID` )
GROUP BY r.`mID` ORDER BY maxrating DESC ) q GROUP BY q.director
ORDER BY q.maxrating DESC
And i am sure this question is taken from the quiz of DB class provided by stanford university
Here is your fiddle
Another way to do that is:
select m.title, max(r.stars) as stars
from rating r
inner join movie m on r.mid = m.mid
group by r.mid
order by m.title
this code should suffice :
select distinct m1.director, m1.title, r1.stars from movie m1
join rating r1 on m1.mID = r1.mID
left join (
select m2.director, r2.stars from movie m2
join rating r2 on m2.mID = r2.mID
) s on m1.director = s.director and r1.stars < s.stars
where s.stars is null and m1.director is not null;
I am having the following two table.
1.Movie Detail (Movie-ID,Movie_Name,Rating,Votes,Year)
2.Movie Genre (Movie-ID,Genre)
I am using the following query to perform join and get the movie with highest rating in each
genre.
select Movie_Name,
max(Rating) as Rating,
Genre from movie_test
inner join movie_genre
where movie_test.Movie_ID = movie_genre.Movie_ID
group by Genre
In the output Rating and Genre are correct but the Movie_Name is incorrect.
can anyone suggest what changes I should make to get the correct movie name along with rating and genre.
SELECT g.*, d.*
FROM MovieGenre g
INNER JOIN MovieDetail d
ON g.MovieID = d.MovieID
INNER JOIN
(
SELECT a.Genre, MAX(b.Rating) maxRating
FROM MovieGenre a
INNER JOIN MovieDetail b
ON a.MovieID = b.MovieID
GROUP BY a.Genre
) sub ON g.Genre = sub.Genre AND
d.rating = sub.maxRating
There is something wrong with your schema design. If a Movie can have many Genre as well as Genre can be contain on many Movie, it should be a three table design.
MovieDetails Table
MovieID (PK)
MovieName
MovieRating
Genre Table
GenreID (PK)
GenreName
Movie_Genre Table
MovieID (FK) -- compound primary key with GenreID
GenreID (FK)
This is a common MySQL problem - specifying non-aggregate/non-aggregated-by columns in an aggregate query. Other flavours of SQL do not let you do this and will warn you.
When you do a query like yours, you are selecting non-aggregate columns in an aggregated group. Since many rows share the same genre, when you select Movie_Name it picks one row at random from each group and displays that one, because there is no general algorithm to guess the row you want and return the values of that.
You might ask 'why does it pick randomly? It could pick the one that max(Rating) belongs to?' but what about other aggregate columns, like avg(Rating)? What row does it pick there? What if two rows have the same max, anyway? Therefore it cannot have an algorithm to pick a row.
To solve a problem like this, you have to restructure your query, something like:
select Movie_Name,
Rating,
Genre from movie_test mt
inner join movie_genre
where movie_test.Movie_ID = movie_genre.Movie_ID
and Rating = (select max(Rating) from movie_test mt2 where mt.Genre = mt2.Genre
group by Genre
limit 1
This will select the row with the rating being the same as the maximum rating for that genre, using a subquery.
Query:
SELECT t.Movie_Name,
t.Rating,
g.Genre
FROM movie_test t
INNER JOIN movie_genre g ON t.Movie_ID = g.Movie_ID
WHERE t.Movie_ID = (SELECT t1.Movie_ID
FROM movie_test t1
INNER JOIN movie_genre g1 ON t1.Movie_ID = g1.Movie_ID
WHERE g1.Genre = g.Genre
ORDER BY t1.Rating DESC
LIMIT 1)
Ugh ok I'm terrible at explaining things, so I'll just give you the quotes and links first:
Problem 4b (near bottom):
4b. List the film title and the leading actor for all of 'Julie Andrews' films.
movie(id, title, yr, score, votes, director)
actor(id, name)
casting(movieid, actorid, ord)
(Note: movie.id = casting.movieid, actor.id = casting.actorid)
My answer (doesn't work):
SELECT title, name
FROM casting JOIN movie
ON casting.movieid = movie.id
JOIN actor
ON casting.actorid = actor.id
WHERE name = 'Julie Andrews'
AND ord = 1
The problem here is that it wants the list of lead actors of movies with 'Julie Andrews' as an actor (who is not necessarily the lead actor), but all I'm doing with my answer is getting the movies where she is the lead (ord = 1).
How do I specify the list of lead actors without 'Julie Andrews' being it? I suspect I have to do something with GROUP BY, but I can't figure out what at the moment...
Edit: Do I need to use a nested SELECT?
There are wonderful ways of doing this with subqueries, but it appears that t this point in the tutorial you're only working with JOINs. The following is how you would do it with only JOINs:
SELECT
movie.title,
a2.name
FROM
actor AS a1
JOIN casting AS c1 ON (a1.id = c1.actorid)
JOIN movie ON (c1.movieid = movie.id)
JOIN casting AS c2 ON (movie.id = c2.movieid)
JOIN actor AS a2 ON (c2.actorid = a2.id)
WHERE
a1.name = 'Julie Andrews'
AND c2.ord = 1
EDIT (more descriptive):
This will give us a table containing all of the movies Julie Andrews acted in. I'm aliasing the actor and casting tables as a1 and c1 respectively because now that we've found a list of movies, we'll have to turn and match that against the casting table again.
SELECT
movie.*
FROM
actor a1
JOIN casting c1 ON (a1.id = c1.actorid)
JOIN movie ON (c1.movieid = movie.id)
WHERE
a1.name = 'Julie Andrews'
Now that we have a list of all movies she acted, we need to join that against the casting table (as c2) and that to the actor table (as a2) to get the list of leading roles for these films:
SELECT
movie.title, -- we'll keep the movie title from our last query
a2.name -- and select the actor's name (from a2, which is defined below)
FROM
actor a1 -- \
JOIN casting AS c1 ON (a1.id = c1.actorid) -- )- no changes here
JOIN movie ON (c1.movieid = movie.id) -- /
JOIN casting AS c2 ON (movie.id = c2.movieid) -- join list of JA movies to the cast
JOIN actor AS a2 ON (c2.actorid = a2.id) -- join cast of JA movies to the actors
WHERE
a1.name = 'Julie Andrews' -- no changes
AND c2.ord = 1 -- only select the star of the JA film
Edit: In aliasing, the 'AS' keyword is optional. I've inserted it above to help the query make more sense
You want to match movies to two potentially separate rows in the casting table: one row where Julie Andrews is the actor, and the second row which may or may not be Julie Andrews, but which is the lead actor for the film.
Julie <---> cast in <---> a movie <---> starring <---> Lead actor
So you need to join to the casting table twice.
SELECT m.title, lead.name
FROM actor AS julie
JOIN casting AS c1 ON (julie.id = c1.actorid)
JOIN movie AS m ON (c1.movieid = m.id)
JOIN casting AS c2 ON (m.id = c2.movieid)
JOIN actor AS lead ON (c2.actorid = lead.id)
WHERE julie.name = 'Julie Andrews'
AND c2.ord = 1;
Remember that "table aliases" reference potentially different rows, even if they are aliases to the same table.
SELECT title, name
FROM casting JOIN movie
ON casting.movieid = movie.id
JOIN actor
ON casting.actorid = actor.id
WHERE ord = 1
and casting.movieid in
(select movieid
from casting
join actor
on actor.id = casting.actorid
where actor.name = 'Julie Andrews')
By the way, this was the answer posted on the site (I just found out about it):
SELECT title, name
FROM movie, casting, actor
WHERE movieid=movie.id
AND actorid=actor.id
AND ord=1
AND movieid IN
(SELECT movieid FROM casting, actor
WHERE actorid=actor.id
AND name='Julie Andrews')
Go figure. :P
select title, name from movie join casting on movie.id=movieid
join actor on actor.id=actorid
where ord=1 and movieid in (select movieid from actor join casting
on actor.id=actorid
where name='julie andrews' and (ord=1 or ord<>1))group by title, name
#Bill Karwin 's answer is good for the direction.
However, the result turns out some movies' title has been appear more than one time.
So we need added a DISTINCT function before title in SELECT row.
SELECT DISTINCT m.title, lead.name
And if you want more quick response, you also could write code in this way.
SELECT DISTINCT m.title, lead.name
FROM actor AS julie
JOIN casting AS c1 ON (julie.id = c1.actorid AND julie.name = 'Julie Andrews')
JOIN movie AS m ON (c1.movieid = m.id)
JOIN casting AS c2 ON (m.id = c2.movieid)
JOIN actor AS lead ON (c2.actorid = lead.id)
WHERE c2.ord = 1;
I ve done simply like this
select distinct title,name from
(select movie.* from movie
inner join casting on (movie.id = casting.movieid)
inner join actor on (casting.actorid = actor.id)
where actor.name = 'Julie Andrews' ) as moviesFromJulie
inner join casting on (moviesFromJulie.id = casting.movieid)
inner join actor on (casting.actorid = actor.id)
where ord = 1
Retreive all movies julie andrews played in, then for those movies retreive all movies and actors for them with ordinal number = 1, and distinct for unique results
Sharing an easy answer to this-
select title, name from movie
join casting on movie.id=movieid
join actor on actor.id=actorid where ord=1 and movie.id in (select movie.id from movie
join casting on movie.id=movieid
join actor on actor.id=actorid where name='Julie Andrews')
SELECT title , name
FROM movie JOIN casting ON (casting.movieid=movie.id) JOIN actor ON (actor.id=actorid)
WHERE (movieid IN (SELECT movieid
FROM casting JOIN actor ON (actor.id=actorid)
WHERE name = 'Julie Andrews')) AND (ord=1)