SQL Query, list from BOTH values? - sql

Pretty sure this can be answered quite quickly but I just can't seem to find a solution online. Might I add also (if you haven't already figured out) that I'm a complete beginner.
The following query lists all movies starring Johnny Depp and all movies starring Helena Bonham Carter. How do I list all movies starring BOTH Johnny and Helena?
Thank you!
SELECT title FROM movies
JOIN stars
ON stars.movie_id = movies.id
JOIN people
ON people.id = stars.person_id
WHERE people.name IN ("Johnny Depp", "Helena Bonham Carter")
ORDER BY title;

See if this works for you, aggregate the title and filter where there are only 2 - assuming a person can only star in a movie once.
select m.title
from movies m
join stars s on s.movie_id = m.id
join people p on p.id = s.person_id
where p.name in ('Johnny Depp', 'Helena Bonham Carter')
group by m.title
having Count(*) = 2
order by m.title;
Also note that using aliases improves the readability and string literals should be in 'single' quotes, double quotes are reserved for delimiters in most databases.

Here is an alternative. Use IN or EXISTS:
select title
from movies
where id in (select movie_id from stars where person_id =
(select id from people where name = 'Johnny Depp')
)
and id in (select movie_id from stars where person_id =
(select id from people where name = 'Helena Bonham Carter')
)
order by title;
This is very quick for the DBMS to do - even with thousands of actors in your database. I suppose the DBMS would get each actor with an index, get their movies with another index and then get the movie title(s) with yet another index. This is extemely fast.

Related

How to SELECT from column WHERE we have multiple conditions in from another TABLE?

I have 3 TABLES:
movies which has title and id columns
stars which has person_id and movie_id columns
people which has id and name columns
I want to write a SQL query to list the titles of all movies in which both Johnny Depp and Helena Bonham Carter starred.
When I write my query I do not get the title which both Johnny Depp and Helena Bonham Carter starred
SELECT title
FROM movies
WHERE id IN ( SELECT movie_id
FROM people
JOIN stars
ON stars.person_id = people.id
WHERE name = "Helena Bonham Carter"
OR name = "Johnny Depp"
)
GROUP BY title;
You can try the below -
SELECT title
FROM movies
WHERE id IN ( SELECT movie_id
FROM people
JOIN stars
ON stars.person_id = people.id
WHERE name in('Helena Bonham Carter' ,'Johnny Depp')
group by movie_id
having count(distinct name)=2
)
GROUP BY title
In your comment you are saying that you want to see titles where both actors are present (used AND), but query says "OR" - one or second one.. SO maybe just logical operand issue?
Query looks good, but haven`t tested :)
You could also formulate your question as "show me the movie rows where a related row for 'Johnny Depp' and 'Helena Bonham Carter' exists". This can be translated to SQL almost literally.
SELECT title
FROM movies
WHERE EXISTS ( SELECT 'x'
FROM stars
JOIN people ON people.id = stars.person_id
WHERE stars.movie_id = movies.id
AND people.name = 'Helena Bonham Carter' )
AND EXISTS ( SELECT 'x'
FROM stars
JOIN people ON people.id = stars.person_id
WHERE stars.movie_id = movies.id
AND people.name = 'Johnny Depp' );

CS50 pset7 movies Q13

For the pset7 Q13 problem, my SQL code is returning back the error:
Result: ambiguous column name: id
At line 1:
This shouldnt be the case because there is a column name that is "id."
Q13:
In 13.sql, write a SQL query to list the names of all people who starred in a movie in which Kevin Bacon also starred.
Your query should output a table with a single column for the name of each person.
There may be multiple people named Kevin Bacon in the database. Be sure to only select the Kevin Bacon born in 1958.
Kevin Bacon himself should not be included in the resulting list.
SELECT name FROM people, stars WHERE people.id = stars.person_id AND stars.movie_id IN (SELECT id FROM movies, stars, people WHERE movies.id = stars.movie_id AND stars.person_id = people.id AND name = "Kevin Bacon" AND birth = 1958);
UPDATED:
SELECT name FROM people, stars WHERE people.id = stars.person_id AND stars.movie_id IN (SELECT movies.id FROM movies, stars, people WHERE movies.id = stars.movie_id AND stars.person_id = people.id AND name = "Kevin Bacon" AND birth = 1958) AND name != "Kevin Bacon";

counting individual elements that meet a certain criteria without duplicates in sqlite3

I'm trying to count all the individual actors from movies in 2004 the problem is when I tried using the count() function it returned how much times every actor appeared in a movie that year.
basically I cant get count() to play well with the GROUP BY function.
SELECT COUNT(name) FROM people
INNER JOIN stars ON stars.person_id = people.id
INNER JOIN movies ON stars.movie_id = movies.id
WHERE movies.year = 2004
GROUP BY name;
relevant tables: movies (id, title, year), stars (movie_id, person_id), people (id, name)
You just need to count the number of DISTINCT person_id in stars (no need to use the people table at all) that have been in movies made in 2004:
SELECT COUNT(DISTINCT person_id) AS num_actors
FROM stars
JOIN movies ON movies.id = stars.movie_id
WHERE movies.year = 2004
Apparently you are not specifying the field you intent to be used for aggregation.Query will return name of actors and respective count of movies. Try below,
SELECT name,COUNT(*) FROM people
INNER JOIN stars ON stars.person_id = people.id
INNER JOIN movies ON stars.movie_id = movies.id
WHERE movies.year = 2004
GROUP BY name;

SQL count by group

I have to following schema
Movie(mvID, title, rating, year)
Director(directorID, firstname, lastname)
Genre(mvID*, genre)
Direct(mvID*, directorID*)
I need to know the director that directed to most movies of say the comedy genre and output their details with the count of how many movies they made in the that genre.
So I have
SELECT Director.DirectorID, Director.FirstName, Director.LastName, COUNT(*)
FROM Direct, Genre, Director
WHERE Direct.mvID = Genre.mvID
AND Genre.genre = 'Comedy'
AND Direct.DirectorID = Director.DirectorID
AND COUNT(*) > ALL
GROUP BY Director.DirectorID, Director.FirstName, Director.LastName
ORDER by COUNT(*) DESC
but I get a group function not allowed error.
The SQL below will solve your problem:
SELECT Director.DirectorID, Director.FirstName, Director.LastName, COUNT(*)
FROM Direct, Genre, Director
WHERE Direct.mvID = Genre.mvID
AND Genre.genre = 'Comedy'
AND Direct.DirectorID = Director.DirectorID
AND rownum = 1
GROUP BY Director.DirectorID, Director.FirstName, Director.LastName
order by COUNT(*) DESC
Specifically, this joins the tables and counts the movies directed by each director for movies of genre 'Comedy'. Then it sorts the row in descending order of count and grabs the first row.
Note you have two many<->many relationships so if you weren't only looking at comedy (i.e. if you ran this across multiple genres), you would probably have to use a different technique (i.e. multiple temp tables or similar virtual aggregates) in order to not have 'double counting in your SQL...
Also note that if two directors have the same count of movies for this genre, only one row would be brought back. You would have to modify the sql slightly if you wanted all directors with the same count of comedies to be returned.
Cheers,
Noah Wollowick
select d.firstname,d.lastname,count(g.mvId)
from Director d
inner join Direct dr on d.directorId=dr.directorId
inner join Genre g on dr.mvId=g.mvId
where g.genre='comedy'
group by d.firstname
having count(g.mvId)=max(g.mvId)

SQL select on a many-to-many table

I've got 3 tables: Movies, Actors, and MovieActors. MovieActors is a many-to-many relationship of Movies and Actors with columns MovieActorId, MovieId, and ActorId
How do I find movies that have a certain set of actors in it? For example I want to find all movies that have both Michael Fassbender (actor Id 1) and Brad Pitt (actor Id 2) in them. What would the query look like?
One way is to join the tables. Filter for the actors and then insure the count has the number of actors you want in it (2 in this case)
SELECT
m.MovieID
FROM
Movies m
INNER JOIN MovieActors ma
ON m.MovieID = ma.MovieID
WHERE
ma.ActorID IN (1,2)
GROUP BY
m.MovieID
HAVING COUNT(DISTINCT ma.ActorID) = 2
DEMO
Note
Thanks to user814064 for pointing out that since Actors can have more than one role on a movie we need to count the DISTINCT ma.ActorID not just * The SQL Fiddle Demo demonstrates the difference
select m.movieid
from movies m
inner join movieactors ma on ma.movieid = m.movieid
where ma.actorid in (1,2)
group by m.movieid
having count(distinct ma.actorid) = 2
To keep it simple, you can just do two in clauses:
select * from Movies m
where m.MovieId in (select MovieId from MovieActors where ActorId = 1)
and m.MovieId in (select MovieId from MovieActors where ActorId = 2)
Performance may not be as good as a single join, but it's clean and easy to read.