PostgreSQL中的逻辑条件

时间:2012-10-31 20:32:00

标签: sql postgresql relational-division

我想要每位导演超过20部电影的男性导演的名字,并且已经投放了他指导的每部电影。如果他投了一部电影,但没有指导它,那没关系,我仍然想要他的名字;如果他导演任何电影但没有投入,我不再想要他了。

SELECT p.firstname, 
    p.lastname 
FROM person p 
WHERE p.gender = 'M' AND
(
    SELECT COUNT(*)
    FROM filmparticipation fpd 
    WHERE p.personid = fpd.personid AND
        fpd.parttype = 'director' AND
        (
            SELECT COUNT(*) 
            FROM filmparticipation c 
            WHERE c.personid = fpd.personid AND
                c.filmid = fpd.filmid AND
                c.parttype = 'cast'
        ) > 0
) >= 20;

这只是我多次尝试之一。作为一个附带问题,为什么它不起作用?我确保我正在检查正确的导演电影ID到演出的电影ID等。

1 个答案:

答案 0 :(得分:1)

看起来像这样:

SELECT p.firstname, p.lastname 
FROM   person p
JOIN  (
   SELECT fd.personid
   FROM   filmparticipation fd
   LEFT   JOIN filmparticipation fc USING (personid, filmid)
   WHERE  fd.parttype = 'director'
   AND    fc.parttype = 'cast'
   GROUP  BY fd.personid
   HAVING count(*) > 20  -- 21+ movies directed (NULL not counted)
   AND    NOT bool_or(fc.personid IS NULL) -- no movie directed but not cast
   ) AS fp USING (personid)
WHERE  p.gender = 'M';

在子查询I LEFT [OUTER] JOIN中,同一部影片的同一个人所指向并投下的所有行 - 他只指向其余部分的地方填充NULL。这就是LEFT JOIN的作用。这假设同一个人只能在同一部电影的同一个角色中出现一次(UNIQUE或PK约束!)。

personid分组必须产生超过20行,并且所有投射personid都不能NULLJOIN到人员表并限制男性,你就完成了。

有很多方法可以解决它,这个应该是最快的方法之一。