help with a sql query joining 2 many-many tables - sql

i want help how to solve this sql problem.
suppose i have 3 tables
Movie
ID
Name
Genre
ID
Name
Movie_Genre (this one is the link for many to many)
FK_MovieID
FK_GenreID
i want to select all the movies that are of genre 1 and genre 3
how is this possible?
i can only select the movies of 1 genre but not the movies that are of 2 genres using
SELECT Movie.ID, Movie.Name
FROM Movies
INNER JOIN Movie_Genre ON Movie_Genre.FK_MovieID=Movie.ID
AND Movie_Genre.FK_GenreID = 1

Use:
SELECT m.id,
m.name
FROM MOVIE m
JOIN MOVIE_GENRE mg ON mg.fk_movieid = m.id
AND mg.fk_genreid IN (1, 3)
GROUP BY m.id, m.name
HAVING COUNT(DISTINCT mg.fk_genreid) = 2
The last line is key to getting rows from both genre's - the DISTINCT means duplicate associations (IE: two instances of genre 1) will be ignored because they are false positives. But the count must equal the number of genres you are looking for.
But COUNT(DISINCT isn't supported by all databases. You should mention what you are using - if not by tag, then in the question... If the primary key for the MOVIE_GENRE table is both fk_movieid and fk_genreid, then it's not an issue. Next best thing would be that both the columns are in a unique constraint/index...

Related

SQL : query to retrieve data

I'm working on a SQL project where i have the tables Actor AlbumId TrackId InvoiceLine and Invoice and i want to retrieve the names of the actors whose tracks are the top 3 sold.
ex(from a table of 10 artists ) .
Drake (300 tracks sold )
Kendrick (233 tracks)
Cardi B (200 tracks)
I'm new to SQL and i have my diagram below . I know that i have to connect the tables of actor album track and invoice to get the 3 max(count(trackid)) from the invoiceline table to give me the names of the actors that have made the specific tracks
Thank you for your time
Below joins the relevant tables together and uses the aggregrate COUNT function to count the number of invoice lines associated with a song.
You may want to use TOP 3 WITH TIES in case there are two artists in third place with same number of sales
SELECT TOP 3
ar.Name
FROM InvoiceLine il
JOIN Track t
ON il.TrackId = t.TrackId
JOIN Album al
ON al.AlbumId = t.AlbumId
JOIN Artist ar
ON ar.ArtistId = al.ArtistId
GROUP BY ar.Name
ORDER BY COUNT(t.TrackId) DESC
If you're looking for the top 3 tracks sold then this will give you the top 3 trackids. Then join this to your Track, Album and Artist tables to get the artist.
SELECT TOP 3 trackid
FROM InvoiceLine
GROUP BY trackid
ORDER BY COUNT(trackid) DESC

SQL ORDER BY number of rows?

How do you ORDER BY number of rows found in another table? I have a table for animals (these are livestock animals) and another table for awards. When an animal wins an award, the award gets added to the awards table.
People want to be able to find the animals who have won the most awards (WHERE award type is 1), ordered from most awards to least. How do I ORDER BY how many awards they have if the awards are in a separate table each with their own row?
SELECT animals.id
FROM animals
LEFT JOIN awards ON animals.id = awards.animalid
WHERE awards.type = 1
ORDER BY...
You would seem to want GROUP BY:
SELECT a.id
FROM animals a LEFT JOIN
awards aw
ON a.id = aw.animalid AND aw.type = 1
GROUP BY a.id
ORDER BY COUNT(aw.animalid) DESC;

How to INTERSECT datas from tables on postgres

I'm having some problems with INTERSECT command. Hope someone could help me.
I want to get the the movieid that appears in the first and second SELECT. After that I want to use these data (that could be in a LIMIT of 10) to receive the titles of the movie in another table.
Something like this, but I'm not doing right:
SELECT movieid
FROM ratings
WHERE votes > 0
INTERSECT SELECT movieid FROM genres WHERE genre = '$_SESSION[genero]'
In this case I should get the movied that appear both on ratings and genres tables.
After this, I want to get these movieids and search the table movies for the movieid and finally show the title. Thank you!
As far as I understood the question, I think this is what you are looking for
select title , movieid from movies
where movieid in
(
SELECT movieid FROM ratings
WHERE votes > 0
INTERSECT
SELECT movieid FROM genres
WHERE genre = '$_SESSION[genero]'
)
select distinct m.title , movieid
from
movies m
inner join
ratings r using (movieid)
inner join
genres g using (movieid)
where r.votes > 0 and g.genre = '$_SESSION[genero]'

sql select actors play two more distinct role in the same movie

the question is to select actors that played 2 or more distinct roles in the same movie.
And I got 3 table, actor (id,name) movie (id,name) and casts(aid,mid,role) (aid is the actor id and mid is the movie id)
I wrote a query like this
select a.name
from actor a, movie m, casts c
where a.id = c.aid and m.id = casts.mid
group by (m.name)
having count(distinct role) > 2;
this didnt print the right result and I didnt see the problem with it.
Thanks for the help!
How about this? Was there any error trying to execute your query?
select actor.name from actor, casts, movie
where casts.aid =actor.id
and casts.mid = movie.id
group by movie.name, actor.name
having count(distinct role) >= 2
As the casts table appears to contain one row per actor, movie, and role (unless you are leaving out other columns), any time a single pair of unique values of aid and mid appears on more than one row, it means the actor played more than one role in that movie. Thus, there is no reason to use distinct. Also because your desired result doesn't contain the movie names, your query doesn't need and shouldn't use the movie table.
If it is true that the cast table has only one row for each unique combination of (aid, mid, and role) then the following should work:
select name
from actor
where id in ( select aid
from casts
group by aid, mid
having count(*) > 1)

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.