左外连接是否相关联?

时间:2013-11-16 18:37:13

标签: sql join outer-join

很容易理解为什么左外连接不是可交换的,但是我在理解它们是否是关联时遇到了一些麻烦。一些在线消息来源表示他们不是,但我没有设法说服自己这是事实。

假设我们有三个表: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)

3 个答案:

答案 0 :(得分:21)

在这个帖子中,据说它们不是关联的:Is LEFT OUTER JOIN associative?

但是,我已经在网上找到了一些书,其中OUTER JOIN是关联的,当最左侧和最右侧的表没有共同的属性时(here)。

这是一个图形演示文稿(MSPaint ftw):

Graphical presentation of impact of left outer joins order

另一种看待它的方式:

既然你说表A与B连接,而B与C连接,那么:

  • 当您第一次加入A和B时,您将获得A中的所有记录。其中一些记录来自B.现在,对于某些那些您从B获得值的行,你从C获得价值。
  • 当您第一次加入B和C时,您和整个表B,其中一些记录具有来自C的值。现在,您从A获取所有记录并加入其中一些记录,其中所有行都来自B加入C.在这里,你再次从A获得所有行,但是其中一些行具有来自B的值,其中一些具有来自C的值。

我认为,在您描述的条件中,根据LEFT连接的顺序会有数据丢失,我认为没有任何可能性。

基于Tilak在他的回答(现已删除)中提供的数据,我构建了一个简单的测试用例:

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                            

在这个特定的例子中,两个解决方案都给出了相同的结果。我想不出任何其他数据集会使这些查询返回不同的结果。

检查SQLFiddle:

答案 1 :(得分:13)

如果你假设你正在加入一个外键,正如你的问题似乎暗示,那么是的,我认为OUTER JOIN保证是关联的,如Przemyslaw Kruglej's answer所述。

但是,鉴于你没有真正指定JOIN条件,迂腐正确的答案是否,它们不能保证是关联的。有两种简单的方法可以违反与不正当ON条款的关联性。

1。其中一个JOIN条件涉及所有3个表中的列

这是违反关联性的一种非常便宜的方式,但严格来说,在您的问题中没有任何内容可以禁止它。使用问题中建议的列名称,请考虑以下两个查询:

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

底层查询甚至不是有效查询,但最重要的是查询。显然,这违反了相关性。

2。尽管一个表中的所有字段都是NULL

,但可以满足其中一个JOIN条件

这样,我们的结果集中甚至可以有不同的行数,具体取决于JOIN的顺序。例如,让B上的A加入条件为A.b_id = B.id,但C上加入B的条件为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;

您可以在此处查看此操作:http://sqlfiddle.com/#!9/d59139/1

答案 2 :(得分:3)

除了之前的答案之外:在Michael M. David,Advanced ANSI SQL Data Modeling and Structure Processing,Artech House,1999,第19-21页中很好地讨论了该主题。可用页面online

我发现特别值得注意的是他讨论了表(LEFT JOIN ...)和join子句(ON ...)必须单独考虑,因此关联性可以指两者(重新安排表子句和re - 安排连接条件,即关于条款)。因此,关联性的概念与例如添加数字的概念不同,它具有两个维度。