很容易理解为什么左外部联接不是可交换的,但是我很难理解它们是否是可交换的。几家在线资源表明不是,但我还没有说服自己就是这种情况。
假设我们有三个表:A,B和C。
令A包含ID和B_ID两列,其中ID是表A的主键,B_ID是与表B的主键相对应的外键。
令B包含两列ID和C_ID,其中ID是表B的主键,C_ID是与表C的主键相对应的外键。
让C包含ID和VALUE两列,其中ID是表C的主键,而VALUE仅包含一些任意值。
那不(A left outer join B) left outer join C应该等于A left outer join (B left outer join C)吗?
(A left outer join B) left outer join C
A left outer join (B left outer join C)
正如您的问题似乎暗示的那样,如果您假设要联接外键,那么可以,我认为OUTER JOIN可以保证是关联的,如Przemyslaw Kruglej的答案所涵盖:
另一种查看方式:
既然您说过表A与B联接,而B与C联接,那么:
第一次加入A和B时,剩下的都是A的所有记录。其中一些具有B的值。现在,对于那些从B获得值的行中的某些记录,您可以从C获得值。 当您第一次连接B和C时,您将遍历整个表B,其中的某些记录都具有C的值。现在,您取走了A的所有记录,并将其中的某些记录与B的所有行都连接了C。 ,同样,您从A获得所有行,但是其中一些具有来自B的值,其中一些具有来自C的值。 在您所描述的条件下,根据LEFT连接的顺序,我看不到任何数据丢失的可能性。
根据蒂拉克在回答中提供的数据(现已删除),我构建了一个简单的测试用例:
CREATE TABLE atab (id NUMBER, val VARCHAR2(10)); CREATE TABLE btab (id NUMBER, val VARCHAR2(10)); CREATE TABLE ctab (id NUMBER, val VARCHAR2(10)); INSERT INTO atab VALUES (1, 'A1'); INSERT INTO atab VALUES (2, 'A2'); INSERT INTO atab VALUES (3, 'A3'); INSERT INTO btab VALUES (1, 'B1'); INSERT INTO btab VALUES (2, 'B2'); INSERT INTO btab VALUES (4, 'B4'); INSERT INTO ctab VALUES (1, 'C1'); INSERT INTO ctab VALUES (3, 'C3'); INSERT INTO ctab VALUES (5, 'C5'); SELECT ab.aid, ab.aval, ab.bval, c.val AS cval FROM ( SELECT a.id AS aid, a.val AS aval, b.id AS bid, b.val AS bval FROM atab a LEFT OUTER JOIN btab b ON (a.id = b.id) ) ab LEFT OUTER JOIN ctab c ON (ab.bid = c.id) ORDER BY ab.aid ;
AID AVAL BVAL CVAL ---------- ---------- ---------- ---------- 1 A1 B1 C1 2 A2 B2 3 A3
SELECT a.id, a.val AS aval, bc.bval, bc.cval FROM atab a LEFT OUTER JOIN ( SELECT b.id AS bid, b.val AS bval, c.id AS cid, c.val AS cval FROM btab b LEFT OUTER JOIN ctab c ON (b.id = c.id) ) bc ON (a.id = bc.bid) ORDER BY a.id ;
ID AVAL BVAL CVAL ---------- ---------- ---------- ---------- 1 A1 B1 C1 2 A2 B2 3 A3
在此特定示例中,似乎两个解决方案都给出了相同的结果。我想不出任何其他数据集,这些数据集会使这些查询返回不同的结果。
但是,鉴于您实际上尚未指定JOIN条件,因此从理论上讲,正确的答案是不,不能保证它们是关联的。有两种简单的方法可以违背带有反常ON子句的关联性。
ON
这是一种违反关联性的廉价方法,但是严格来说,您的问题中没有任何内容可以禁止它。使用问题中建议的列名,考虑以下两个查询:
-- This is legal SELECT * FROM (A JOIN B ON A.b_id = B.id) JOIN C ON (A.id = B.id) AND (B.id = C.id) -- This is not legal SELECT * FROM A JOIN (B JOIN C ON (A.id = B.id) AND (B.id = C.id)) ON A.b_id = B.id
最底下的查询甚至不是有效的查询,但最顶上的查询是。显然,这违反了关联性。
这样,根据JOIN的顺序,我们甚至可以在结果集中拥有不同数量的行。例如,让在B上加入A的条件为A.b_id = B.id,但在C上加入B的条件为B.id IS NULL。
A.b_id = B.id
B.id IS NULL
因此,我们得到了这两个查询,它们的输出截然不同:
SELECT * FROM (A LEFT OUTER JOIN B ON A.b_id = B.id) LEFT OUTER JOIN C ON B.id IS NULL; SELECT * FROM A LEFT OUTER JOIN (B LEFT OUTER JOIN C ON B.id IS NULL) ON A.b_id = B.id;
\