双外连接

时间:2014-10-09 08:23:01

标签: sql postgresql outer-join

我有一个表People,一个表Permission和一个表Action。允许在人与行动之间提供多对多的关系。

我的目标很简单:我想在People中寻找一个人,我希望看到权限中列出的权限,以及每个可用的操作,无论该人是否拥有权限。

请注意,Permission中不需要表示People的成员。因此,“John”只有在获得数据库中写入的权限时才被允许做某事。

理想情况下,结果看起来像:

+-------------------------------------------+
+ People.name | Action.name        |Allowed |
+-------------------------------------------+
| John Doe    | Launching missiles | N      |
| John Doe    | Deleting code      | Y      |
+-------------------------------------------+

在我到达那里之前,我只想简单地用每个数据构建一个简单的查询。 获取某人的许可列表,即使他没有出现在权限表中也很容易:

SELECT * FROM people pp LEFT OUTER JOIN permission pr ON pp.id = pr.people_id 
WHERE pp.name = 'John';

获取权限和操作列表很简单:

SELECT * FROM permission pr LEFT OUTER JOIN action a ON pr.action_id = a.id

然而,我似乎无法执行一个双外连接,可以获得我想要的一切:

SELECT * FROM people pp LEFT OUTER JOIN permission pr ON pp.id = pr.permission_id
   LEFT OUTER JOIN people WHERE pp.name = 'John'

显示约翰,事实上他没有得到许可......但没有任何行动。

换句话说,结果看起来像:

+-----------------------------------------+
+ Name    | People_id | Action_id |Action |
+-----------------------------------------+
| John    |           |           |       |
+-----------------------------------------+

我想要的时候:

+-----------------------------------------------------------+
+ Name    | People_id | Action_id |Action                   |
+-----------------------------------------------------------+
| John    |           |           | Launching missiles      |
| John    |           |           | Deleting codes          |
| John    |           |           | (every other actions)   |
+-----------------------------------------------------------+

那么,我想要的可能吗?如果是这样,我该如何实现呢? (我正在使用PostgreSQL)。

编辑:这是一个sqlfiddle:http://sqlfiddle.com/#!2/6d502

2 个答案:

答案 0 :(得分:2)

SELECT pp.name, pr.id_people, pr.id_action, a.name as action_name
 FROM people pp
 CROSS JOIN action a
 LEFT JOIN permission pr
   ON pr.id_people = pp.id
  AND pr.id_action = a.id

SQLFiddle:http://sqlfiddle.com/#!15/5a7b1/4

按人名过滤添加到查询:

WHERE pp.name = 'John'

答案 1 :(得分:1)

这应该有用。

SELECT 
    P.name as "people.name", 
    IFNULL(pm.id_people,''), 
    IFNULL(pm.id_action,''), 
    A.name as "action.name"
FROM Action A
CROSS JOIN People P
LEFT JOIN permission pm 
    ON pm.id_action = a.id
    AND pm.id_people = p.id
WHERE p.name = 'John'