sql : join and group by - sql

Having 3 tables:
movie(id, title, yr, score, votes,
director) actor(id, name)
casting(movieid, actorid, ord)
Q:Which were the busiest years for
'John Travolta'. Show the number of
movies he made for each year.
A: My try is syntactically worng. why ?
select yr, count(*)
from
(actor join casting
on (actor.id = casting.actorid)
join
on (movie.id = casting.movieid)
group by yr
having actor.name='John Travolta'

You are missing the second table name after join
use where not having
Try this:
select yr, count(*)
from actor
join casting on actor.id = casting.actorid
join movie on movie.id = casting.movieid -- you were missing table name "movie"
where actor.name='John Travolta' -- "where", not "having"
group by yr
Also note the consistent formatting I used. If you use a good format, it's easier to find syntax errors
FYI, having is used for aggregate functions, eg having count(*) > 3

Remove the ( ) from around the table name and add movie to your second join.
select yr, count(*)
from actor join
casting on actor.id = casting.actorid join
movie on movie.id = casting.movieid
group by yr
having actor.name='John Travolta'
EDIT:
You need to switch your having to a where because havings are use for aggregate functions in conjunctions with your group by.
select yr, count(*)
from actor join
casting on actor.id = casting.actorid join
movie on movie.id = casting.movieid
where actor.name = 'John Travolta'
group by yr

To join u have to specify table ure joining, should be
join movie
on movie.id = casting.movieid

Related

SQL How to use info from created table

SELECT yr, COUNT(title) AS g FROM movie
JOIN casting ON id = movieid
JOIN actor ON actorid = actor.id
WHERE name = 'John Travolta'
AND g = 1
GROUP BY yr
--> I want g to work, but I don't know how to use info from same query.
You can't use g at that moment because you're trying to use an aggregate result before it's being aggregated. You need to use the HAVING clause.
SELECT yr, COUNT(title) AS g FROM movie
JOIN casting ON id = movieid
JOIN actor ON actorid = actor.id
WHERE name = 'John Travolta'
GROUP BY yr
HAVING COUNT(title) = 1

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.

sqlzoo joinII exercise - movie databases 4a

This is question is sqlzoo, and I wrote following code, but I feel it is too redundant
SELECT year, freq
FROM (SELECT yr AS year,count(title) AS freq
FROM movie, actor, casting
WHERE name= 'John Travolta'
AND movie.id=movieid
AND actor.id=actorid
GROUP BY yr) AS a
WHERE freq=(
SELECT MAX(freq)
FROM (SELECT yr AS year,count(title) AS freq
FROM movie, actor, casting
WHERE name= 'John Travolta'
AND movie.id=movieid
AND actor.id=actorid
GROUP BY yr) AS b
)
why cannot it be like this?
SELECT year, freq
FROM (SELECT yr AS year,count(title) AS freq
FROM movie, actor, casting
WHERE name= 'John Travolta'
AND movie.id=movieid
AND actor.id=actorid
GROUP BY yr) AS a
WHERE freq=(
SELECT MAX(freq)
FROM a
)
In cases like this it may be helpful to use CTE's (Common Table Expression). That's the only way you can re-use a subquery. Look how you can use ROW_NUMBER to find the largest frequency. I have also updated the old school FROM A, B, C WHERE ... to the new school FROM A INNER JOIN B ... (I'm not 100% sure the JOIN criteria are correct though.)
WITH a AS
(
SELECT
yr AS year,
COUNT(title) AS freq
FROM
movie
INNER JOIN
casting ON movie.id = casting.movieid
INNER JOIN
actor ON actor.id = casting.actorid
WHERE
name = 'John Travolta'
GROUP BY
yr),
b AS
(
SELECT
year, freq,
ROW_NUMBER() OVER (ORDER BY freq DESC) as RowNum
FROM a
)
SELECT year, freq
FROM b
WHERE RowNum = 1
Whenever you are writing sub-queries the inner ones are evaluated first and then the outer queries.In your second query you are using alias "a" which doesn't exist actually.That is the reason you will get an error in the second query and you cannot use it.The first query is the correct one syntactically.

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'