【问题标题】:Getting wrong answer when trying to output a an actors roles尝试输出演员角色时得到错误答案
【发布时间】:2021-03-04 10:56:13
【问题描述】:

我想弄清楚如何获得Daniel Radcliffe 的职业历史。但是,我得到的结果与 Daniel Radcliffe 无关。

CREATE TABLE person (
  id integer primary key,
  name text not null
);

CREATE TABLE movie (
  id integer primary key,
  name text not null
);

CREATE TABLE casts (
  movie_id integer not null,
  person_id integer not null,
  played_as text not null,
  foreign key (movie_id) references movie(id),
  foreign key (person_id) references person(id)
);

CREATE TABLE crew (
  movie_id integer not null,
  person_id integer not null,
  job text not null,
  foreign key (movie_id) references movie(id),
  foreign key (person_id) references person(id)
);

CREATE TABLE famous_level (
  movie_id integer not null,
  person_id integer not null,
  level integer not null,
  foreign key (movie_id) references movie(id),
  foreign key (person_id) references person(id)
);

INSERT INTO person (id, name) VALUES (1, 'Daniel Radcliffe'), (2, 'Emma Watson'), (3, 'Robert Downey Jr.'), (4, 'Joss Whedon');
INSERT INTO movie (id, name) VALUES (1, 'Harry Potter movie'), (2, 'The Avengers');
INSERT INTO casts (movie_id, person_id, played_as) VALUES (1, 1, 'Harry Potter'), (1, 2, 'Hermione Granger'), (2, 3, 'Tony Stark');
INSERT INTO crew (movie_id, person_id, job) VALUES (1, 1, 'Writer'), (1, 4, 'Director'), (2, 2, 'Director'), (2, 1, 'Writer');
INSERT INTO famous_level (movie_id, person_id, level) VALUES (1, 1, 1), (1, 2, 3), (2, 3, 2), (1, 4, 2);

我知道Daniel Radcliffe的ID是1

SELECT
  m.name,
  ct.played_as,
  cr.job
FROM movie m
JOIN crew cr ON m.id = cr.movie_id
JOIN casts ct ON m.id = ct.movie_id
JOIN famous_level f ON m.id = f.movie_id
JOIN person p ON cr.person_id = p.id
WHERE p.id = 1
ORDER BY f.level ASC

我想得到与此类似的结果,其中played_as 或job 列上都有NULL 值

+--------------------+--------------+--------+
|        name        |  played_as   |  job   |
+--------------------+--------------+--------+
| Harry Potter movie | Harry Potter | NULL   |
| Harry Potter movie | NULL         | Writer |
| The Avengers       | NULL         | Writer |
+--------------------+--------------+--------+

我得到的结果:http://www.sqlfiddle.com/#!17/28dd0

【问题讨论】:

    标签: sql database postgresql join select


    【解决方案1】:

    因为您想为每部电影的每个played_asjob 获取一行,您需要创建一个包含所有played_asjob 值的表,您可以使用UNION询问。当played_as 有效时,该查询为job 返回NULL,反之亦然。然后可以将其JOINed 到moviepersonfamous_level 表以过滤person_id 并按level 排序:

    SELECT m.name,
           r.played_as,
           r.job
    FROM movie m
    JOIN (
      SELECT movie_id, person_id, played_as, NULL as job
      FROM casts
      UNION ALL 
      SELECT movie_id, person_id, NULL, job
      FROM crew
    ) r ON r.movie_id = m.id
    JOIN person p ON p.id = r.person_id
    LEFT JOIN famous_level f ON f.movie_id = m.id AND f.person_id = p.id
    WHERE p.id = 1
    ORDER BY COALESCE(f.level, 99)
    

    输出:

    name                played_as       job
    Harry Potter movie  (null)          Director
    Harry Potter movie  (null)          Writer
    Harry Potter movie  Harry Potter    (null)
    The Avengers        (null)          Writer
    

    Demo on SQLFiddle

    请注意,您需要在 movie_idperson_id 上都使用 JOINfamous_level 以避免在输出中获得额外的行。由于并非所有电影/人物组合都有famous_level,因此您需要在level 值上使用LEFT JOINCOALESCE,以便当它为NULL 时。

    【讨论】:

    • 感谢您的回答,我的问题是,如果我将其插入到表 INSERT INTO crew (movie_id, person_id, job) VALUES (1, 1, 'Director') 中会怎样。我怎么能看到丹尼尔现在的完整职业生涯。我也需要 Famous_level,因为我将它用于ORDER BY level ASC
    • 如果工作存在,我怎样才能让played_as 为空?
    • 您想为每部电影在played_asjob 中获取一行(正如您在输出中显示的那样,但不是我的查询当前产生的结果)?
    • 是的,我想为每部电影的每个played_as 或工作获得一行
    • 只需将LEFT JOIN famous_level 更改为JOIN famous_level。在这种情况下,您也可以删除 ORDER BY 子句中的 COALESCE
    猜你喜欢
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 2022-12-07
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 1970-01-01
    相关资源
    最近更新 更多