2010-09-23 154 views
16

我有三个表:R,S和P.SQL连接三个表,连接优先

表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) 

,如果我想要第二个连接被捆绑与S不是R,就像如果我可以使用括号:

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

或者是,R,S和P之间的乘积的已经是一个自然的行为?

+0

你能否解释一下这部分“如果我想第二个连接被束缚不是以R” 眼下表的连接为R带S加入,然后留下P. – 2010-09-23 16:05:37

+0

加入我试着了解是否有一种方法可以优先考虑连接,就像它们是算术运算符一样。如果这在连接条件中是隐含的,我不明白。 – vulkanino 2010-09-23 16:08:21

+0

给我们一个你希望实现的与普通联接不同的数据例子,我们可以更好地告诉你该怎么做。派生表可能做你想做的事情,但我不确定你想要什么。 – HLGEM 2010-09-23 17:25:29

回答

26

所有类型的外连接和正常连接处于相同的优先级类别,并且运算符在查询的给定嵌套级别上从左到右生效。您可以将连接表达式放在括号的右侧,使其首先生效;请记住,您必须移动现在位于您放置伙伴的联接之外的联接的ON子句。

(PostgreSQL的例子)

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

的AB加入生效第一,但我们可以强制BC联接到做第一生效:

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

澄清:所有加入运算符具有相同的优先级,并且都具有从左到右的关联性。这是减法( - )和除法(/)操作符几乎在所有编程语言中工作的方式。改变操作数的顺序对其“优先级”(SQL语法的一个方面而不是任何情况下的操作数)没有影响。这样做会利用连接的从左到右的关联性来实现组合连接的所需语义。但它不会改变表达中任何事物的优先性和关联性 - 只会改变其解释的上下文。 – 2016-03-24 19:37:37

+0

够公平的。什么是第二个词,表达一个运算符在另一个运算符的影响之前的效果,但不是因为已经采用了这个效果而没有优先权? – rakslice 2016-03-26 20:07:46

+0

换句话说。另外,尽管我不喜欢用别人的专业词汇来表达它的词典定义(不,我不知道),但真正研究我的齿轮的东西就像“结合性”,其中专业术语是已被占用的数学术语由计算世界。 – rakslice 2016-03-26 20:28:20

1

第二次加入与S相连,如您明示状态JOIN P ON (P.id = S.fkp) - 在连接中没有引用来自R的列。

+0

好的,但一般来说,没有办法优先考虑连接? – vulkanino 2010-09-23 16:04:43

+0

我不认为SQL以您想的方式工作。 Paul Spangle的答案描述了SQL如何“思考”连接。 – 2010-09-23 16:16:16

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) 
+0

考虑我必须加入3个表格,而不是2个。 – vulkanino 2010-09-23 16:20:14

+1

它只是从左到右工作。我能想到的唯一方法是将一个完整的派生表放在一些括号中。 – 2010-09-23 16:30:15

1

连接没有优先权,它是关联操作。旧的逗号分隔语法清楚地表明了,新的语法(大概是为了模仿关系代数而熟悉的)令人困惑。然而,外连接(单独使用或与常规连接一起使用)不具有关联性。

+3

考虑到OP询问LEFT JOINS,JOINS关联的陈述很容易引起误解。 – Taemyr 2014-02-28 10:19:58

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 

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

+1

右连接与这个问题无关,没有人说他们是一样的。 – Hogan 2016-07-29 17:48:09