很容易理解为什么左外连接不是可交换的,但是我在理解它们是否是关联时遇到了一些麻烦。一些在线消息来源表示他们不是,但我没有设法说服自己这是事实。
假设我们有三个表: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)
?
答案 0 :(得分:21)
在这个帖子中,据说它们不是关联的:Is LEFT OUTER JOIN associative?
但是,我已经在网上找到了一些书,其中OUTER JOIN是关联的,当最左侧和最右侧的表没有共同的属性时(here)。
这是一个图形演示文稿(MSPaint ftw):
另一种看待它的方式:
既然你说表A与B连接,而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
条款的关联性。
这是违反关联性的一种非常便宜的方式,但严格来说,在您的问题中没有任何内容可以禁止它。使用问题中建议的列名称,请考虑以下两个查询:
-- 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
。
因此,我们得到了这两个查询,输出结果非常不同:
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 - 安排连接条件,即关于条款)。因此,关联性的概念与例如添加数字的概念不同,它具有两个维度。