简体   繁体   中英

Constructing a Complex SQL Query with Joins

Sorry for the nondescript title but I'm not sure how to phrase the question. Say we have the following tables:

    people
    id|created_at|updated_at|name             |
    --|----------|----------|-----------------|
     1|          |          |Quentin Tarantino|
     2|          |          |Terry O'Quinn    | 
     3|          |          |Sam Jackson      |
     4|          |          |Michael Madsen   |
     5|          |          |Bryan Cranston   |

    crew_members
    id|created_at|updated_at|type    |
    --|----------|----------|--------|
     1|          |          |Actor   |
     2|          |          |Director|
     3|          |          |Writer  |

    movies
    id|created_at|updated_at|title         |
    --|----------|----------|--------------|
     1|          |          |Pulp Fiction  |
     2|          |          |Reservoir Dogs|

    series
    id|created_at|updated_at|title             |
    --|----------|----------|------------------|
     1|          |          |Lost              |
     2|          |          |Breaking Bad      |
     3|          |          |The Tarantino Show|

    credits
    id|created_at|updated_at|person_id|character   |crew_member_id|
    --|----------|----------|---------|------------|--------------|
     1|          |          |        1|            |             2|
     2|          |          |        1|Jimmy       |             1|
     3|          |          |        1|            |             3|
     4|          |          |        2|John Locke  |             1|
     5|          |          |        3|Jules       |             1|
     6|          |          |        4|Mr Blonde   |             1|
     7|          |          |        5|Walter White|             1|
     8|          |          |        1|Mr Brown    |             1|
     9|          |          |        1|Himself       |             1|

    credit_feature_person
    id|created_at|updated_at|person_id|credit_id|movie_id|series_id|
    --|----------|----------|---------|---------|--------|---------|
     1|          |          |        1|        1|       1|        0|
     2|          |          |        1|        2|       1|        0|
     3|          |          |        1|        3|       1|        0|
     4|          |          |        1|        1|       2|        0|
     5|          |          |        1|        8|       2|        0|
     6|          |          |        1|        3|       2|        0|
     7|          |          |        2|        4|       0|        1|
     8|          |          |        3|        5|       1|        0|
     9|          |          |        4|        6|       2|        0|
    10|          |          |        5|        7|       0|        2|
    11|          |          |        1|        9|       0|        3|

If I want to show all movies a person (say, Tarantino with id 1) was involved in, plus what they did in that movie, I can do this:

    select m.title as movie, coalesce(character,type) as role 
    from "credits" 
    inner join "credit_feature_person" on "credits"."id" = "credit_id" 
    inner join "people" on "credit_feature_person"."person_id" = "people"."id" 
    inner join "movies" m on "credit_feature_person"."movie_id" = "m"."id"
    inner join "crew_members" on "credits"."crew_member_id" = "crew_members"."id"
    where "credits"."person_id" = 1;

    //result
         movie      |   role   
    ----------------+----------
     Pulp Fiction   | Director
     Pulp Fiction   | Jimmy
     Pulp Fiction   | Writer
     Reservoir Dogs | Director
     Reservoir Dogs | Mr Brown
     Reservoir Dogs | Writer
    (6 rows)

But I also want to include the series they worked on too, and the result to look like


         title      |   role   
    ----------------+----------
     Pulp Fiction   | Director
     Pulp Fiction   | Jimmy
     Pulp Fiction   | Writer
     Reservoir Dogs | Director
     Reservoir Dogs | Mr Brown
     Reservoir Dogs | Writer
    The Tarantino Show | Himself
    (7 rows)

I keep trying different things and either get syntax errors or 0 results. Any ideas? I expected to at least be able to do this:

    select coalesce(m.title, s.title) as title, coalesce(character,type) as role 
    from "credits" 
    inner join "credit_feature_person" on "credits"."id" = "credit_id" 
    inner join "people" on "credit_feature_person"."person_id" = "people"."id" 
    inner join "movies" m on "credit_feature_person"."movie_id" = "m"."id"
    inner join "series" s on "credit_feature_person"."series_id" = "s"."id"
    inner join "crew_members" on "credits"."crew_member_id" = "crew_members"."id"
    where "credits"."person_id" = 1;

But this doesn't work either, it returns zero results for some reason.

Edit: Solution is to use left joins on movies and series

select coalesce(m.title,s.title) as title, coalesce(character,type) as role 
from "credits" 
inner join "credit_feature_person" on "credits"."id" = "credit_id" 
inner join "people" on "credit_feature_person"."person_id" = "people"."id" 
left join "movies" m on "credit_feature_person"."movie_id" = "m"."id"
left join "series" s on "credit_feature_person"."series_id" = "s"."id"
inner join "crew_members" on "credits"."crew_member_id" = "crew_members"."id"
where "credits"."person_id" = 1; 

The problem is that the links to movies and series are mutually exclusive. When you attempt an inner join to the one side that's missing each of the rows is eliminated from the results. Those two joins need to be left outer joins.

select coalesce(m.title, s.title) as title, coalesce(character,type) as role 
from "credits" 
    inner join "credit_feature_person" on "credits"."id" = "credit_id" 
    inner join "people" on "credit_feature_person"."person_id" = "people"."id" 
    inner join "crew_members" on "credits"."crew_member_id" = "crew_members"."id"
    left outer join "movies" m on "credit_feature_person"."movie_id" = "m"."id"
    left outer join "series" s on "credit_feature_person"."series_id" = "s"."id"
    where "credits"."person_id" = 1
order by title, role;

http://sqlfiddle.com/#!15/45440/5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM