SQL加入三个表,加入优先级

时间:2010-09-23 15:56:50

标签: sql

我有三个表:R,S和P.

表R通过外键与S连接; 应该至少是S中的一条记录,所以我可以加入:

SELECT
        *
    FROM 
        R
    JOIN    S ON (S.id = R.fks)

如果S中没有记录,那么我没有任何行,那没关系。

然后表S与P连接,其中记录为P可能存在也可能不存在并与S连接。

所以我做了

SELECT
        *
    FROM 
        R
    JOIN    S ON (S.id = R.fks)
    LEFT JOIN P ON (P.id = S.fkp)

如果我希望将第二个JOIN绑定到S而不是R,如果我可以使用括号,该怎么办?

SELECT
        *
    FROM 
        R
    JOIN    (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp))

或者这是R,S和P之间笛卡尔积的自然行为吗?

4 个答案:

答案 0 :(得分:33)

所有类型的外连接和普通连接都在同一优先级中,并且运算符在查询的给定嵌套级别从左到右生效。您可以将连接表达式放在括号中的右侧,以使其首先生效;只记得你必须移动现在在你加入parens的连接之外的连接的ON子句。

(PostgreSQL示例)

SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);

a-b连接首先生效,但是我们可以通过将它放在括号中来强制b-c连接生效,如下所示:

SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);

通常,您可以通过移动连接并更改外连接方向来表达相同的内容而无需额外的括号,例如。

SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);

答案 1 :(得分:2)

当您加入第三个表时,您的第一个查询

SELECT
        *
    FROM 
        R
    JOIN    S ON (S.id = R.fks)

就像您要加入第三个表的派生表。因此,如果R JOIN S没有产生任何行,那么加入P将永远不会产生任何行(因为您正在尝试加入空表)。

因此,如果您正在寻找优先规则,那么在这种情况下,它只是使用LEFT JOIN而不是JOIN进行设置。

但是,我可能会误解你的问题,因为如果我在编写查询,我会交换SR。例如

SELECT
        *
    FROM 
        S
    JOIN    R ON (S.id = R.fks)

答案 2 :(得分:1)

第二个连接 与S绑定为明确状态JOIN P ON (P.id = S.fkp) - 在连接中没有引用R中的列。

答案 3 :(得分:0)

with a as (select 1 as test union select 2)
select * from a left join
a as b on a.test=b.test and b.test=1 inner join
a as c on b.test=c.test 
go
with a as (select 1 as test union select 2)
select * from a inner join
a as b on a.test=b.test  right join
a as c on b.test=c.test and b.test=1

理想情况下,我们希望上述两个查询是相同的。但是,它们不是 - 所以任何人说在任何情况下都可以用左连接替换正确的连接是错误的。只有使用正确的连接才能获得所需的结果。