(SQL ZOO) Lead actor in Julie Andrews movies - sql

SQL Zoo
https://sqlzoo.net/wiki/More_JOIN_operations
No. 12:
Lead actor in Julie Andrews movies
List the film title and the leading actor for all of the films 'Julie Andrews' played in.
Did you get "Little Miss Marker twice"?
Julie Andrews starred in the 1980 remake of Little Miss Marker and not the original(1934).
Title is not a unique field, create a table of IDs in your subquery (What does this mean?)
What I wrote was this but it says I'm wrong, don't know why:
SELECT title, name
FROM (movie JOIN casting ON movie.id = casting.movieid) JOIN actor ON actor.id = casting.actorid
WHERE title IN
(SELECT title FROM casting JOIN actor ON casting.actorid = actor.id
where actor.name = 'Julie Andrews')
AND ord = 1

WHERE title IN
(SELECT title FROM casting JOIN actor ON casting.actorid = actor.id
where actor.name = 'Julie Andrews')
There is no title column in either casting or actor. So you have accidentally correlated this subquery - the title is scoped from outside the subquery so you effectively have something like
where 1 in
(select 1
from casting JOIN actor ON casting.actorid = actor.id
where actor.name = 'Julie Andrews'
)
Which will be true if that subquery returns any rows. Always be clear which row source a column should come from.
You probably meant to select the movieid column from casting and use that as a filter against movie.id similar to your join in the first subquery:
SELECT movie.title, actor.name
FROM movie
JOIN casting ON movie.id = casting.movieid
JOIN actor ON actor.id = casting.actorid
WHERE movie.id IN
(SELECT casting.movieId FROM casting JOIN actor ON casting.actorid = actor.id
where actor.name = 'Julie Andrews')
AND casting.ord = 1

Had a quick go, this goes the trick
/* Create a derived table of the relevant IDs*/
with j as (
select movieid
from casting c join actor a on a.id=c.actorid
where a.name='julie andrews'
)
/*
Now use this as a starting point to join to the
relevant tables to fetch the required actors from
the movieIDs from the derived table
*/
select m.title, a.name
from j join movie m on m.id=j.movieid
join casting c on c.movieid=j.movieid
join actor a on a.id=c.actorid
where c.ord=1

Related

How to list all the people who have worked with 'Art Garfunkel'?

I have 3 tables actor, movie, casting. I have to find the people who have worked with actor "ART Garfunkel".
I have solution but I am not able to understand how the following query works.
**movie** **actor** **casting**
id id movieid
title name actorid
yr ord
director
budget
gross
SELECT a.name
FROM (SELECT movie.*
FROM movie
JOIN casting
ON casting.movieid = movie.id
JOIN actor
ON actor.id = casting.actorid
WHERE actor.name = 'Art Garfunkel') AS m
JOIN (SELECT actor.*, casting.movieid
FROM actor
JOIN casting
ON casting.actorid = actor.id
WHERE actor.name != 'Art Garfunkel') as a
ON m.id = a.movieid;
one more solution:
SELECT actor.name FROM casting
JOIN movie ON movie.id=casting.movieid
JOIN actor ON actor.id=casting.actorid
WHERE actor.name !='Art Garfunkel'
AND
movie.id IN(SELECT movie.id FROM casting
JOIN movie ON movie.id=casting.movieid
JOIN actor ON actor.id=casting.actorid
WHERE actor.name='Art Garfunkel')
Easy Solution:
SELECT distinct actor.name
FROM movie
JOIN casting
ON casting.movieid = movie.id
JOIN actor
ON actor.id = casting.actorid
where movie.id in (select movieid from casting join actor on id =actorid where
actor.name = 'Art Garfunkel') and actor.name <> 'Art Garfunkel'
Here's a simplified version that does the same thing:
select actor.name
from (
select movieid from casting
join actor on actor.id = casting.actorid
and actor.name = 'Art Garfunkel'
) ag_movies
join casting on ag_movies.movieid = casting.movieid
join actor on actor.id = casting.actorid
and actor.name != 'Art Garfunkel'
Yours follows roughly the same steps:
Get the movieid for all movies Art Garfunkel was in.
Find the cast lists for all those movies.
Get the artist names from the cast lists that are not Art Garfunkel.
The casting table is a cross-lookup table which allows many actors to act in many movies. Through the casting table we have to find all the movies Art was in and then reverse that to find the other actors in those movies.
The joins mean the result will only contain rows from both tables which match the join criteria. So on actor.id = casting.actorid and actor.name = 'Art Garfunkel' connects the tables by the matching IDs but limits the results to only those IDs where the actor name is Art's. The join as used in these queries means the same as intersection from set theory.
The sub-select inside the parenthesis creates a temporary table (named ag_movies in this example) that can be used by the parent query just like any other table.
Here is a solution for MySQL:
SELECT name FROM actor JOIN casting ON actor.id = actorid JOIN movie ON movie.id = movieid WHERE movie.id IN (
SELECT movieid FROM casting
WHERE actorid IN (SELECT id FROM actor WHERE name = 'Art Garfunkel')
) AND actor.name != 'Art Garfunkel';
It's difficult to understand your question... here is my suggested solution:
SELECT
*
FROM
Actor A
INNER JOIN
Casting C
ON
C.ActorID = A.ID
WHERE C.MovieID IN (
SELECT
C.MovieID
FROM
Casting C
INNER JOIN
Actor A
ON
C.ActorID = A.ID
WHERE
Actor = 'Art Garfunkel'
)
WHERE
Actor <> 'Art Garfunkel'
The sub-query first finds all movies that the actor is in. The second outer query finds all actors that have acted in a movie that is returned from said sub query.
SELECT name FROM actor
JOIN casting ON actor.id = actorid WHERE casting.movieid IN
(SELECT movieid FROM casting WHERE name != 'Art Garfunkel' AND
actorid in (SELECT actor.id FROM actor WHERE name = 'Art Garfunkel'))
SELECT name FROM actor
JOIN casting ON id=casting.actorid
WHERE movieid IN(
SELECT movieid FROM casting
WHERE actorid IN(
SELECT id FROM actor
WHERE name = 'Art Garfunkel'))
AND name <> 'Art Garfunkel'
SELECT DISTINCT a.NAME
FROM casting c
JOIN actor a
ON c.actorid = a.id
WHERE c.movieid IN (SELECT c.movieid
FROM casting c
JOIN actor a
ON c.actorid = a.id
WHERE a.NAME = 'Art Garfunkel')
AND a.NAME <> 'Art Garfunkel'
ORDER BY 1
The code below will solve the issue:
select distinct name
from actor
join casting on id=actorid
where actorid IN
(select actorid
from casting
where movieid IN
(select movieid
from casting
where actorid =
(select id from actor where
name= 'Art Garfunkel')
)
)
and
name <> 'Art Garfunkel'
SELECT name
FROM actor
JOIN casting ON (actorid=id)
WHERE movieid IN (SELECT movieid
FROM casting
JOIN actor ON (actorid=id)
WHERE name='Art Garfunkel')
AND name<>'Art Garfunkel'
The queries posted in question are quite convoluted. A simple query will help you understand the logic flow better. Starting from subquery we select the list of 'movieid' starring 'Art Garfunkel'. The main query selects all the actors in the list of movies returned by subquery. In the final step we have to remove the entries of 'Art Garfunkel' himself else his name will also come in the list. 'Art Garfunkel' could not have worked with 'Art Garfunkel' himself.
SELECT name FROM actor
JOIN casting on actor.id= actorid
WHERE casting.movieid IN
(SELECT movie.id FROM movie
JOIN casting ON movie.id = movieid
JOIN actor ON actor.id = actorid
WHERE actor.name = 'Art Garfunkel') AND name <> 'Art Garfunkel'
I find translating my code in root level easier to understand before unravelling. So it goes like this:-
Get names of actors WHERE Art Garfunkel stars in AND name IS NOT Art Garfunkel
SELECT name
FROM actor
WHERE id IN(SELECT c.actorid
FROM casting c
JOIN actor a ON c.actorid = a.id
WHERE c.movieid IN(
SELECT c.movieid
FROM casting c
JOIN actor a
ON a.id = c.actorid
WHERE a.name = 'Art Garfunkel')) AND NOT name = 'Art Garfunkel'
select a.name from actor a join casting c on a.id=c.actorid where c.movieid in
(select c.movieid from casting c join actor a on c.actorid=a.id where a.name='Art Garfunkel') and a.name <> 'Art Garfunkel'
select name from actor a join
casting c on c.actorid=a.id
where movieid in (select movieid from casting
where actorid in (select id from actor
where name ='Art Garfunkel'))
and name <> 'Art Garfunkel';
this is the easiest solution i have got so far for this question:
select actor.name from actor
/* fetch all the actor names from actor_ids (fetched below) */
where id in
(select casting.actorid from casting where movieid in
/* fetch all the actor_ids from movie_ids (fetched below) */
(select movieid from casting join actor on actor.id=casting.actorid
where actor.name='Art Garfunkel'))
/* fetch all the movie_ids in which 'Art Garfunkel' has worked */
and actor.name <> 'Art Garfunkel'
This simple solution without any heavy join operation is for those who aim for better performamce
select name from actor where id in (select actorid from casting where movieid in (select movieid from casting where actorid in (select id from actor where name = 'Art Garfunkel'))) and name != 'Art Garfunkel'
select name from casting
join movie on movieid=id
join actor on actorid=actor.id
where movieid in (select movieid from casting
join actor on actorid=id
where name='Art Garfunkel')
order by name
You can achieve your solution by executing this:
SELECT DISTINCT a.NAME
FROM actor a
JOIN casting c
ON a.id = c. actorid
WHERE movieid IN(SELECT movieid
FROM casting
JOIN actor
ON actor.id = casting.actorid
WHERE NAME = 'Art Garfunkel')
AND NAME <> 'Art Garfunkel'

selected statement in joining table

movie:
id ,title,yr,director,budget,gross
actor:
id,name
casting:
movieid,actorid,ord
I have a question on this I has been asking to (List the films together with the leading star for all 1962 films.) [Note: the ord field of casting gives the position of the actor. If ord=1 then this actor is in the starring role]
My answer was this:
select
title, name
from
movie
join
casting on movie.id = casting.movieid
join
actor on actor.id = casting.actorid
where
yr = 1962 and movie.id = casting.movieid and actor.id = casting.actorid and casting.ord = 1
group by
title
But what my problem was I can get close to the answer, I have the problem at the ord part because some of the casting do not have 1 for the actor that just showing two, so it will not display on the output.
How could I make it select ord =1 or ord =2 (but not both)(and 1 have higher priority)
Hope anyone can help me this.
select title,coalesce (c.name,c21.name) as actorname from movie m
left join (select * from casting where ord=1) c on m.id= c.movieid
left join (select * from casting where ord=2) c1 on c.movieid = c1.movieid
left join actor a on a.id= c.actorid
where yr=1962
Hope this will output your expected result
Select title,name
From Movie M
Cross Apply (Select top 1 movieid,actorid,ord from Casting Order By ord) as Cast
Inner join Actor A On A.id = Cast. actorid
Use CROSS APPLY (http://technet.microsoft.com/en-us/library/ms175156(v=sql.105).aspx) with a subquery which is ordered by the 'ord' column and has a TOP(1) clause.
SELECT
M.title
, CA.name
FROM
movie AS M
CROSS APPLY (
SELECT TOP(1)
actor.name
FROM
casting C
INNER JOIN actor A
ON C.actorid = A.id
WHERE
M.id = C.movieid
ORDER BY
ord
ASC
) AS CA
I have 2 answers:
SELECT movie.title, (select actor.name from actor where actor.id = casting.actorid)
FROM movie
JOIN casting
ON movie.id =casting.movieid
WHERE movie.yr = 1962 and casting.ord = 1
But then I realized that you can chain joins:
SELECT movie.title, actor.name
FROM movie
JOIN casting ON movie.id=casting.movieid
JOIN actor ON casting.actorid = actor.id
WHERE movie.yr = 1962 and casting.ord = 1
The second one is clearly much simpler. (There's no need to nest a SELECT statement).
To have it select either or, do ... and (casting.ord = 1 xor casting.ord = 2).
To order it by 1, try something like Order by casting.ord in (1,2). (I haven't tested that.

Select statement returns the incorrect results

I have been trying to figure out the correct SQL for question number 13 in this tutorial. None of the other questions concern me, just #13.
Essentially, what the question asks is to find out all the movies that 'Julie Andrews' played in, and from that result, select the actors who played the leading actors in those movies. Sounds simple enough, but everything I try is failing. The following:
select title, name from movie
join casting on movie.id=movieid
join actor on actorid=actor.id
where (name = 'Julie Andrews' )
and ord=1
selects the movies that she was in and she was the lead actor. What I need is the lead actors for movies she was in, not the movies she played the lead in.
Does anyone have any suggestions?
select movie.title, actor.name
from movie, actor, casting, (SELECT movieid from casting join actor
on actor.id=casting.actorid where actor.name = 'Julie Andrews') JAM
where movie.id = JAM.movieid and actor.id = casting.actorid
and casting.movieid=JAM.movieid and casting.ord=1
group by movie.title
Try this:
select m.title, a.name
from movie m
join casting c on m.id = c.movieid
and ord = 1
join actor a on a.id = c.actorid
where exists (select *
from casting c2
join actor a2 on c2.actorid = a2.id
and a2.name = 'Julie Andrews'
where c2.movieid = m.id
)

SQLzoo | JOIN operation

I'm trying to solve question 13 of JOIN tutorial in SQLzoo (http://sqlzoo.net/wiki/More_JOIN_operations)
The question ask to list the film title and the leading actor for all of the films 'Julie Andrews' played in.
I've produced the following script, but somewhere is wrong.
SELECT title, actor.name FROM
movie JOIN casting ON movie.id=movieid
JOIN actor ON actor.id=actorid
WHERE ord=1
AND title = ALL
(SELECT title FROM
movie JOIN casting ON movie.id=movieid
JOIN actor ON actor.id=actorid
WHERE actor.name='Julie Andrews')
The right script is:
SELECT m.title,
a.name
FROM movie m
JOIN casting c
ON m.id = c.movieid
AND c.ord = 1
JOIN actor a
ON a.id = c.actorid
WHERE m.id IN (SELECT m1.id
FROM movie m1
JOIN casting c1
ON m1.id = c1.movieid
JOIN actor a1
ON a1.id = c1.actorid
WHERE a1.name = 'Julie Andrews')
I've noticed that if I'm using the column m.title as a proxy in the WHERE statement the script takes more time to run and the SQLzoo server stop it. Instead, using the m.id column makes things faster to load. Perhaps is a good practice always prefer to check digits instead of letters when possible.
Another issue on my initial scripts was setting an EQUAL operator instead of IN. The sub-query returns more than 1 row, thus is necessary the use of an IN operator.
Try this :
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')
Easy Solution:
select movie.title, actor.name FROM movie
JOIN casting
ON casting.movieid = movie.id
JOIN actor
ON actor.id = casting.actorid
where ord = 1 and
movieid in (select movieid from casting join actor on id = actorid where name = 'Julie Andrews' )
I think this is the right way to you get it.
SELECT m.title, a.name FROM
movie m JOIN casting c ON c.id = m.movieid
JOIN actor a ON a.id=m.actorid
WHERE m.ord=1
AND m.title = ALL
(SELECT m1.title FROM
movie m1 JOIN casting c1 ON c1.id=m1.movieid
JOIN actor a1 ON a1.id=m1.actorid
WHERE a1.name='Julie Andrews');
If you have to display your tables with column names then i will be modify this query
select title, name from movie
join casting on (casting.movieid =movie.id)
join actor on (actor.id = casting.actorid)
where ord =1
and movieid in (select movie.id from movie
join casting on (casting.movieid =movie.id)
join actor on (actor.id = casting.actorid)
where name = 'Julie Andrews')
SELECT title,name
FROM movie
JOIN casting ON (movieid=movie.id AND ord=1)
JOIN actor ON (actor.id=actorid)
WHERE movieid IN (SELECT movieid
FROM movie
JOIN casting ON (movieid=movie.id)
JOIN actor ON (actor.id=actorid)
WHERE actor.name='Julie Andrews')
Starting from subquery: Select all the 'movieid' of movies with 'Julie Andrews' in them and use it as a filter in WHERE
Now join all the 3 tables with a specific condition that you only select the 'actorid' with 'ord'=1 ('ord'=1 means that the actors name is on top of order of actors). This will only select the rows/records containing the actor ids of lead actors. In the end just retrieve these leading actors name from 'actor' table.
SELECT title,name FROM
casting join movie on movie.id=movieid and ord=1
join actor on actor.id=actorid
WHERE movie.id in (
SELECT movie.id FROM
movie join casting on movie.id=movieid
join actor on actor.id=actorid
WHERE name='Julie Andrews' )

again new query. i am trying to solve this from one hour. please help

Query : List the film title and the leading actor for all of 'Julie Andrews' films.
there are three tables
movie (id, title, yr, score, votes, director)
actor (id, name)
casting (movieid, actorid, ord)
select movie.title,actor.name as cont
from movie
join casting on (movie.id=casting.movieid)
join actor on (casting.actorid=actor.id)
where actor.name='Julie andrews'
actually i can't get how to find the leading actor.
You almost for sure will need a sub query to achieve this one way or another.
select movie.title, actor.name
from movie
inner join casting
on movie.id = casting.movieid
and casting.ord = 1 --Assuming this is the cast order flag
inner join actor
on casting.actorid = actor.id
where movie.id in (
select movie.id
from movie
inner join casting
on movie.id = casting.movieid
and casting.actorid = {your actorID in this case Julie Andrew's id
)
Disclaimer: I didn't test this as you didn't provide an easy way to do so.
If you really wanted to go by name (which could lead to false positive) then you can add an extra join to the in clause sub query.
Firstly, you shouldn't use id for the key column, use movieid and actorid. This makes joins easier:
select movie.title, lead.name as cont
from actor
join casting using (actorid)
join movie using (movieid)
join casting as leadrole using (movieid)
join actor as lead on (leadrole.actorid = lead.actorid)
where actor.name = 'Julie andrews'
and leadrole.ord = 1
This assumes that the lead actor's ord column is 1. It is also completely untested, so you will probably need to debug it.
Assuming the lead role is ord = 1 you can try this out (I didn't test it)
EDIT:
select
M.title,
(select
A1.name
from
casting CI
join
actors A1
on
A1.id = CI.actorid
where
CI.movieid = M.id
and
CI.ord = 1) as LeadingActor
from
movie M
join
casting C
on
M.id = C.movieid
join
actor A
on
C.actorid = A.id
where
A.name='Julie andrews'