sqlzoo "More Join" #15 - sql

Can someone show me why my solution doesn't work for this challenge?
http://sqlzoo.net/wiki/More_JOIN_operations
15. List the films released in the year 1978 ordered by the number of actors in the cast, then by title.
SELECT title, COUNT(actorid) AS actors FROM movie
JOIN casting ON id = movieid
WHERE yr = 1978
GROUP BY title
ORDER BY actors DESC

Because you're missing the second-level ORDER BY term. It should be:
ORDER BY actors DESC, title
(The question doesn't explicitly ask for descending order, but their official “correct answer” is ordered that way.)

Since the requirements ask you to order by the number of actors and then title. Therefore, you have to add title in Order by clause:
SELECT title, COUNT(actorid) AS actors FROM movie
JOIN casting ON id = movieid
WHERE yr = 1978
GROUP BY title
ORDER BY actors DESC, title

select distinct a1.name from actor a1
join casting c1 on c1.actorid = a1.id
join movie m1 on c1.movieid = m1.id
where m1.id in (
select distinct m.id from movie m
join casting c on c.movieid = m.id
join actor a on c.actorid = a.id
where a.name = 'Art Garfunkel')
and a1.name <> 'Art Garfunkel'

Related

SQL Query: List all actors who appeared in 40 or more thrillers, in descending order

For the database schema:
actor (id, fname, lname, gender)
movie (id, name, year)
directors (id, fname, lname)
casts (pid, mid, role)
movie_directors (did, mid)
genre (mid, genre)
The task I am trying to solve is to:
List all actors who appeared in 40 or more thrillers, in descending order of the number of thrillers they appeared in. Return the actors’ first and last names and the number of thriller movies each of them appeared in.
The current query I am using is:
SELECT a.fname, a.lname, COUNT(DISTINCT m.id)
FROM Actor a, Casts c, Movie m, genre g
WHERE a.id = c.pid
AND c.mid = m.id
AND c.mid = g.mid
AND g.genre = 'Thriller'
GROUP BY a.id, a.fname, a.lname
HAVING COUNT(DISTINCT m.id) >= 40
ORDER BY COUNT(DISTINCT m.id) DESC
As this is a homework question, I have uploaded this response to Gradescope. It is returning only the result:
Test Failed: False is not true
which is not very helpful, and as a direct result makes it hard to find the error in my logic. I am also not able to post the verbatim wrong response as a result of the unhelpful error message. What is wrong with my query, and what can I change to make it work?
There is nothing functionally wrong with your query, there must something wrong with GradeScope, whatever that is. Note that, you don't actually need to include a.id in your GROUP BY.
I'd prefer a more modern approach to joins, e.g. using the JOIN keyword.
Fiddle Here
SELECT
aim.fname,
aim.lname,
aim.movieCount
FROM
(
SELECT
a.fname,
a.lname,
COUNT(DISTINCT m.id) movieCount
FROM
actor a
JOIN
casts c
ON c.pid = a.id
JOIN
movie m
ON m.id = c.mid
JOIN
genre g
ON g.mid = m.id
WHERE
g.genre = 'Thriller'
GROUP BY
a.fname,
a.lname
) aim
WHERE
aim.movieCount > 39
ORDER BY
aim.movieCount DESC;

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' )

SQL Join Query help

I am doing some SQL exercise and having this problem, this query below gives me a 'half correct' result because I only want the row(s) with the most title to be displayed, this query is displaying all records. Can someone help? Thanks.
Question:
Which were the busiest years for 'John Travolta'. Show the number of movies he made for each year.
Tables:
movie (id, title, yr, score, votes, director)
actor (id, name)
casting (movieid, actorid, ord)
Query:
select yr, max(title)
from
(
select yr, count(title) title from movie
join casting
on (movie.id=casting.movieid)
join actor
on (casting.actorid=actor.id)
where actor.name="John Travolta"
group by yr Asc
) a
The question asks
Which were the busiest years?
... plural. So, what were his top 5 years?
select top 5
m.yr
,count(*)
from actor as a
join casting as c
join movie as m
on m.movieid = c.movieid
on c.actorid = a.actorid
where a.name = 'John Travolta'
group by
m.yr
order by
count(*) desc
However, the second part of the question specifies that you should
Show the number of movies he made for each year.
So far our query doesn't account for years in which John made no movies... so, this might be where your half correct comes into play. That said, you may want to create a table variable filled with year values from 1954 through the current year... and left join off of that.
declare #year table
(
[yr] int
)
declare #currentYear int = datepart(year,getdate())
while #currentYear >= 1954 begin -- Travolta was born in 1954!
insert #year values (#currentYear)
set #currentYear -= 1
end
select
y.yr
,count(m.movieid)
from #year y
left join movies as m
join casting as c
join actor as a
on a.actorid = c.actorid
and a.name = 'John Travolta'
on c.movieid = m.movieid
on m.yr = y.yr
group by
y.yr
order by
,count(m.movieid) desc
[Edit: based on comments] And a final query to return all years whose count matches the highest of any year.
;with TravoltaMovies as
(
select
m.yr
,count(*) as [Count]
from actor as a
join casting as c
join movie as m
on m.movieid = c.movieid
on c.actorid = a.actorid
where a.name = 'John Travolta'
group by m.yr
)
select
*
from TravoltaMovies as tm
where tm.[Count] = (select max([Count]) from TravoltaMovies)
the answer is:
SELECT y.yr,MAX(y.count)
FROM(
SELECT movie.yr,COUNT(movie.yr) AS count
FROM (movie JOIN casting ON (movie.id=movieid)) JOIN actor ON (actor.id=actorid)
WHERE name='John Travolta'
GROUP BY yr
ORDER BY COUNT(movie.yr) DESC) y
This is much easy solution.
select yr, count(yr)
from movie
join casting on movie.id = movieid
join actor on actorid = actor.id
where name = 'John Travolta'
group by yr
having count(yr) > 2**
Happy to help
select TOP 1 yr, title
from
(
select yr, count(title) title from movie
join casting
on (movie.id=casting.movieid)
join actor
on (casting.actorid=actor.id)
where actor.name="John Travolta"
group by yr Asc
) a
ORDER BY title DESC
Just add a TOP selection and an ORDER BY.
The aggregation is unnecessary.
Thanks all this is the query:
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
)
This a simple answer using both join and sub-query concept
select yr,count(title) from movie
inner join casting on
movie.id=casting.movieid
where actorid= (select id from actor where name ='John Travolta')
group by yr
having count(title)>2
Here is an easier solution with explanation-
First we make a join of all the tables
Then we put a category filter on name with name= 'John Travolta'
Now we put a group function on yr so that we have yr and corresponding count(yr)
Solution wants to have years with count>2 only so we apply that filter on grouped data by using 'having' clause
select yr, count(yr) from movie
join casting on movie.id=movieid
join actor on actor.id=actorid
where name= 'John Travolta'
group by yr
having count(yr)>2
Hope this helps, I dont see a need to write a Procedure for this.

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'