1

假设我们在关系数据库中有三个表:

Person {id, name}
Obstacle {id, name}
Person_overcomes_obstacle {person_id, obstacle_id}

我想写一个查询,告诉我是否至少有一个人克服了所有障碍。想法?

4

4 回答 4

4

我注意到我是唯一一个使用自然表别名的人Person_overcomes_obstacle

为此,您需要一个关系除法查询。

您可以计算 Person_overcomes_obstacle 中的障碍和匹配记录,并返回 2 个数字匹配的记录,或者以另一种方式查看它,以查找没有尚未克服的障碍的人。

SELECT p.id, p.name /*Or use COUNT(*) or wrap in Exists 
                     if you don't care about ids and names*/
FROM Person p
WHERE NOT EXISTS
   (SELECT * FROM Obstacle o
    WHERE NOT EXISTS 
    (
       SELECT * FROM Person_overcomes_obstacle poo
       WHERE poo.person_id = p.id and o.id = poo.obstacle_id
    )
)
于 2010-07-18T21:38:16.137 回答
3
SELECT 
    p.name,
    COUNT(DISTINCT oo.obstacle_id) AS OBSTACLES_COMPLETED
FROM 
    person p

    JOIN person_overcomes_obstacle oo
    ON oo.person_id = p.person_id

GROUP BY 
    p.name

HAVING 
    COUNT(DISTINCT poo.obstacle_id) = (SELECT COUNT(id) FROM obstacle)
于 2010-07-18T21:25:14.580 回答
1

这个 SELECT 应该返回没有人克服的障碍的数量。如果计数为零,则至少一个人已经克服了所有障碍。

SELECT count(*)
  FROM (SELECT po.person_id, o.obstacle_id
          FROM Obstacle o
          LEFT OUTER JOIN Person_overcomes_obstacle po
            ON (o.obstacle_id = po.obstacle_id)) t
WHERE t.person_id IS NULL

您也可以这样做,以获得相同的效果(并且可能获得更好的性能):

SELECT count(*)
  FROM Obstacle o
 WHERE NOT EXISTS (SELECT 1
                     FROM Person_overcomes_obstacle po
                    WHERE po.obstacle_id = o.obstacle_id)

编辑:正如评论中所指出的,上述两个查询仅证明没有人克服的障碍,而不是单个人克服了所有障碍。

除此之外,应该仍然可以证明单个用户已经克服了所有障碍,而无需查询 Person 表:

SELECT t.personid, count(*)
  FROM (SELECT DISTINCT po.person_id, o.obstacle_id
          FROM Obstacle o
          JOIN Person_overcomes_obstacle po
            ON (o.obstacle_id = po.obstacle_id)) t
 GROUP BY t.persion_id
 HAVING count(*) = (SELECT count(*)
                      FROM obstacle)
于 2010-07-18T21:31:44.630 回答
1

利用:

SELECT poo.person_id
    FROM PERSON_OVERCOMES_OBSTACLE poo
GROUP BY poo.person_id
    HAVING COUNT(DISTINCT poo.obstacle_id) = (SELECT COUNT(*) 
                                                                        FROM OBSTACLE)

这是一种不太可能表现良好的替代方案:

SELECT x.person_id
   FROM (SELECT poo.person_id,
                         COUNT(DISTINCT poo.obstacle_id) AS obs_overcome,
                         (SELECT COUNT(*) 
                             FROM OBSTACLE) AS obs_total
                 FROM PERSON_OVERCOMES_OBSTALCE poo
          GROUP BY poo.person_id) x
 WHERE x.obs_overcome = x.obs_total

无论哪种情况,您都可以根据需要加入 PERSON 表以获取更多信息 - 或者您可以对person_id任一查询进行计数,以了解有多少人完成了记录的所有障碍。

于 2010-07-18T22:25:22.670 回答