I try to display each pair of actors, the two actors have not played on anyone
common movie genre while at the same time the genre that one has played together with the genre which has been played by the other being at least 7
I did this:
select a1.actor_id as i8opoios1,a2.actor_id as i8opoios2,((count(distinct(g1.genre_name))+count(distinct(g2.genre_name)))>=7) as result from actor as a1
inner join actor as a2 on a1.actor_id!=a2.actor_id
inner join role as r1 on a1.actor_id=r1.actor_id
inner join movie as m1 on m1.movie_id=r1.movie_id
inner join movie_has_genre as mg1 on mg1.movie_id=m1.movie_id
inner join genre as g1 on mg1.genre_id=g1.genre_id
inner join role as r2 on a2.actor_id=r2.actor_id
inner join movie as m2 on m2.movie_id=r2.movie_id
inner join movie_has_genre as mg2 on mg2.movie_id=m2.movie_id
inner join genre as g2 on mg2.genre_id=g2.genre_id
where a1.actor_id<a2.actor_id and mg1.genre_id!=mg2.genre_id
group by a1.actor_id,a2.actor_id;
This query returns me all the pair of actors who have not played on anyone
common movie genre and as a result a 1(TRUE) if combined they played on 7 or more genre and 0(FAlSE) if they hadnt.My question is if anyone has an idea on how can i return only the true statements.
Tables and their columns:
actor(actor_id,name)
role(actor_id,movie_id)
movie(movie_id,title)
movie_has_genre(movie_id,genre_id)
genre(genre_id,gender_name)
Add the condition to your where clause to limit the rows.
SELECT
a1.actor_id as i8opoios1,
a2.actor_id as i8opoios2,
IF((count(distinct(g1.genre_name))+count(distinct(g2.genre_name)))>=7,1,0) as result
FROM actor as a1
INNER JOIN actor as a2
on a1.actor_id != a2.actor_id
INNER JOIN role as r1
on a1.actor_id = r1.actor_id
INNER JOIN movie as m1
on m1.movie_id = r1.movie_id
INNER JOIN movie_has_genre as mg1
on mg1.movie_id = m1.movie_id
INNER JOIN genre as g1
on mg1.genre_id = g1.genre_id
INNER JOIN role as r2
on a2.actor_id = r2.actor_id
INNER JOIN movie as m2
on m2.movie_id = r2.movie_id
INNER JOIN movie_has_genre as mg2
on mg2.movie_id = m2.movie_id
INNER JOIN genre as g2
on mg2.genre_id = g2.genre_id
WHERE a1.actor_id < a2.actor_id
AND mg1.genre_id != mg2.genre_id
HAVING IF((count(distinct(g1.genre_name))+count(distinct(g2.genre_name)))>=7,1,0) = 1
GROUP BY a1.actor_id,a2.actor_id;
Related
So I have to do a query where I am asked to find the count of directors who, for every pair of movies' genres, have directed both. I thought I should take two instances of genre id and two instances of directors id and find those where g_id's are different but dir_id are the same,so I tried something like this
select distinct g1.genre_id as genre1,
g2.genre_id as genre2,
count(distinct mhd1.director_id) as directors_count
from genre g1, genre g2, movie_has_genre mhg1,movie_has_genre
mhg2,movie_has_director mhd1,movie_has_director mhd2
where
(g2.genre_id <> g1.genre_id) and (mhg1.genre_id = g1.genre_id)
and (mhg2.genre_id = g2.genre_id) and (mhd1.movie_id = mhg1.movie_id)
and (mhd2.movie_id = mhg2.movie_id) and (mhd1.director_id =mhd2.director_id)
group by g1.genre_id, g2.genre_id;
Base is
actor(actor_id,first_name,last_name,gender)
director(director_id,first_name,last_name)
role(movie_id,actor_id,role)
genre(genre_id,name)
movie(movie_id,title,year,rank)
movie_has_director(movie_id,director_id)
movie_has_genre(genre_id,movie_id)
but it is not working. What am I missing there? Thank you
EDIT problem seems to be I get both (a,b) and (b,a) pairs while I should get only (a,b) with a
First you need kind of a cross join to get all combinations of two genres: genre g1 join genre g2 on g2.id > g1.id. Then you need to join movie_has_genre and movie_has_director to both (g1 and g2) and only keep rows where the director is the same (md2.director_id = md1.director_id). The rest is basic GROUP BY and COUNT:
select g1.name as genre1,
g2.name as genre2,
count(distinct md1.director_id) as directors_count
from genre g1
join genre g2 on g2.id > g1.id
join movie_has_genre mg1 on mg1.genre_id = g1.id
join movie_has_genre mg2 on mg2.genre_id = g2.id
join movie_has_director md1 on md1.movie_id = mg1.movie_id
join movie_has_director md2 on md2.movie_id = mg2.movie_id
and md2.director_id = md1.director_id
group by g1.id, g2.id
Adding on to #Paul's answer, you can get rid of duplicate (a,b), (b,a) by using DISTINCT, LEAST, GREATEST
select DISTINCT LEAST(g1.name,g2.name) as genre1,
GREATEST(g1.name,g2.name) as genre2,
count(distinct md1.director_id) as directors_count
from genre g1
join genre g2 on g2.id <> g1.id
join movie_has_genre mg1 on mg1.genre_id = g1.id
join movie_has_genre mg2 on mg2.genre_id = g2.id
join movie_has_director md1 on md1.movie_id = mg1.movie_id
join movie_has_director md2 on md2.movie_id = mg2.movie_id
and md2.director_id = md1.director_id
group by g1.id, g2.id
I am not sure what to call this but basically, my database has games that can be played by 1 to 4 players.
The Games table has 4 foreign keys to the PlayerGames table. GameFirstPlace, GameSecondPlace... etc. They can be null.
If they are not they point to an entry in the PlayerGames table.
The PlayerGames table has, among other things, a foreign key to the players table. The players table has PlayerName.
I want to get the PlayerName for all the participants of a Game where PlayerGame is not null.
That is, if my game looks like:
GameFirstPlace GameSecondPlace GameThirdPlace GameFourthPlace
6 7 NULL NULL
Then PlayerGame id 6 has PlayerID = 7 and PlayerGame id 7 has PlayerID 3
Then Player with id 7 PlayerName = 'Jack' and Player with id 3 PlayerName = 'Mary'
Then my query might return:
GameID FirstPlaceName SecondPlaceName ThirdPlaceName FourthPlaceName
5 'Jack' 'Mary' NULL NULL
What might the select query for something like this look like?
SELECT
Game.GameID
,Player1.Name AS FirstPlaceName
,Player2.Name AS SecondPlaceName
,Player3.Name AS ThirdPlaceName
,Player4.Name AS FourthPlaceName
FROM
Game
LEFT OUTER JOIN PlayerGame as PlayerGame1 ON Game.GameFirstPlace = PlayerGame1.Id
LEFT OUTER JOIN Player AS Player1 ON PlayerGame1.PlayerId = Player1.Id
LEFT OUTER JOIN PlayerGame as PlayerGame2 ON Game.GameSecondPlace = PlayerGame2.Id
LEFT OUTER JOIN Player AS Player2 ON PlayerGame2.PlayerId = Player2.Id
LEFT OUTER JOIN PlayerGame as PlayerGame3 ON Game.GameSecondPlace = PlayerGame3.Id
LEFT OUTER JOIN Player AS Player3 ON PlayerGame3.PlayerId = Player3.Id
LEFT OUTER JOIN PlayerGame as PlayerGame4 ON Game.GameFirstPlace = PlayerGame4.Id
LEFT OUTER JOIN Player AS Player4 ON PlayerGame4.PlayerId = Player4.Id
You're going to have to duplicate all of the join logic four ways.
select
g.GameID,
p1.PlayerName as FirstPlaceName,
p2.PlayerName as SecondPlaceName,
p3.PlayerName as ThirdPlaceName,
p4.PlayerName as FourthPlaceName
from
Games g
left outer join PlayerGames pg1 on pg1.PlayerID = g.GameFirstPlace
left outer join Players p1 on p1.PlayerID = pg1.PlayerID
left outer join PlayerGames pg2 on pg2.PlayerID = g.GameSecondPlace
left outer join Players p2 on p2.PlayerID = pg2.PlayerID
left outer join PlayerGames pg3 on pg3.PlayerID = g.GameThirdPlace
left outer join Players p3 on p3.PlayerID = pg3.PlayerID
left outer join PlayerGames pg4 on pg4.PlayerID = g.GameFourthPlace
left outer join Players p4 on p4.PlayerID = pg4.PlayerID
I'm guessing that your PlayerGame table has a GameID which you could take advantage of to simplify the join logic. The output gets a little more complicated in return but the query will probably perform better.
SELECT
g.GameID,
min(case when p.PlayerID = g.GameFirstPlace then p.PlayerName end) AS FirstPlaceName,
min(case when p.PlayerID = g.GameSecondPlace then p.PlayerName end) AS SecondPlaceName,
min(case when p.PlayerID = g.GameThirdPlace then p.PlayerName end) AS ThirdPlaceName,
min(case when p.PlayerID = g.GameFourthPlace then p.PlayerName end) AS FourthPlaceName
FROM
Games g
inner join PlayerGames pg on pg.GameID = g.GameID
inner join Players p on p.PlayerID = pg.PlayerID
GROUP BY
g.GameID
SELECT GameID,
P1.PlayerName FirstPlaceName,
P2.PlayerName SecondPlaceName,
P3.PlayerName ThirdPlaceName,
P4.PlayerName FourthPlaceName
FROM Games G
LEFT JOIN PlayerGames P1
ON G.GameFirstPlace = P1.PlayerID
LEFT JOIN PlayerGames P2
ON G.GameSecondPlace = P2.PlayerID
LEFT JOIN PlayerGames P3
ON G.GameThirdPlace = P3.PlayerID
LEFT JOIN PlayerGames P4
ON G.GameFourthPlace = P4.PlayerID
task; id
task_assign; id, task_id
task_state; id, assign_id
states; id, state_id, define_id
I want containing at selected IDs in other table
SELECT DISTINCT t.id,t.* FROM tasks AS t
INNER JOIN task_assign AS ta1 ON ta1.task_id=t.id
INNER JOIN task_state AS ts1 ON ts1.assign_id=ta1.id
INNER JOIN states AS s1 ON s1.id=ts1.state_id AND s1.define_id=14
INNER JOIN task_assign AS ta2 ON ta2.task_id=t.id
INNER JOIN task_state AS ts2 ON ts2.assign_id=ta2.id
INNER JOIN states AS s2 ON s2.id=ts2.state_id AND s2.define_id=21
.
.
.
INNER JOIN task_assign AS ta5 ON ta5.task_id=t.id
INNER JOIN task_state AS ts5 ON ts5.assign_id=ta5.id
INNER JOIN states AS s5 ON s5.id=ts5.state_id AND s5.define_id=25
this works but when multiplied request it slowing down. Is there another method?
SELECT
t.id
FROM
tasks t
INNER JOIN
task_assign ta1
ON ta1.task_id = t.id
INNER JOIN
task_state ts1
ON ts1.assign_id = ta1.id
INNER JOIN
states s1
ON s1.id = ts1.state_id
AND s1.define_id IN (14,25)
GROUP BY
t.id
HAVING
COUNT(DISTINCT s1.define_id) = 2
EDIT - to explain to the OP what this does...
This will first retrieve all records where the define_id is either 14 OR 25, but the HAVING clause will only allow the query to return those who have both.
So let's same I'm trying to find actors who are in two movies together (for the purpose of a degrees of separation page). I have databases as such (this is just some made up data):
actors
id first_name last_name gender
17 brad pitt m
2 kevin bacon m
movies
id name year
20 benjamin button 2008
roles
a_id m_id role
17 20 Mr. Benjamin Button
So I want to return the names of the movies which both actors are in. I have the first and last names of two actors.
I'm having a lot of trouble getting this to work. What I'm having trouble with, specifically, is the SELECT part
SELECT name FROM movies JOIN . . .
I'm starting with first_name and last_name values for each
You must join twice:
SELECT m.name movie_name
FROM movies m join roles r1 on
r1.m_id = m.id join actors a1 on
r1.a_id = a1.id join roles r2 on
r2.m_id = m.id join actors a2 on
r2.a_id = a2.id
WHERE
a1.first_name = 'brad' and a1.last_name = 'pitt' and
a2.first_name = 'kevin' and a2.last_name = 'bacon'
Show all actor combinations per film:
SELECT m.name movie_name, a1.id actor1, a2.id actor2
FROM movies m join roles r1 on
r1.m_id = m.id join actors a1 on
r1.a_id = a1.id join roles r2 on
r2.m_id = m.id join actors a2 on
r2.a_id = a2.id
WHERE
a1.id < a2.id
The < ensures that each combination is only reported once.
select m.name,group_concat(concat_ws(' ',a.first_name,a.last_name) order by a.last_name) as actors
from actors as a
inner join roles as r on a.id = r.a_id
inner join movies as m on m.id = r.m_id
where r.a_id in (2,17)
group by r.m_id
having count(r.a_id) = 2
order by m.name
declare #FirstActorID int,
#SecondActorID int;
select m.[name]
from
movies m
inner join [roles] r1 on r1.m_id = m.id and r1.a_id = #FirstActorID
inner join [roles] r2 on r2.m_id = m.id and r2.a_id = #SecondActorID
Consider I have three tables:
Movies (movie 1, movie 2, etc)
Categories (action, suspense, etc)
Movies_Categories (movie 1 -> action, movie 1 -> suspense, movie 2 -> suspense, etc)
How could I select only the movies that belong or don't belong to a specific category using only 1 query?
Thanks!
Belongs:
SELECT m.*
FROM movies m
INNER JOIN movies_categories mc
ON m.id = mc.movie_id
INNER JOIN categories c
ON c.id = mc.category_id
AND c.name = 'action';
Doesn't belong:
SELECT m.*
FROM movies m
LEFT OUTER JOIN (SELECT mc.movie_id
FROM movies_categories mc
INNER JOIN categories c
ON c.id = mc.category_id
AND c.name = 'action') mcx
ON m.id = mcx.movie_id
WHERE mcx.movie_id IS NULL
SELECT m.*,
IF(mc.movie_id IS NULL, 'doesnt belong', 'belongs')
FROM Movies m
LEFT JOIN Movies_Categories mc ON mc.movie_id = m.id
AND mc.category_id = (SELECT id
FROM categories
WHERE name = 'action')