简体   繁体   English

MySQL在多个外部联接的子句中放置条件

[英]MySQL placement of conditions in on-clauses of multiple outer joins

As a follow up to In SQL / MySQL, what is the difference between "ON" and "WHERE" in a join statement? 作为后续工作, 在SQL / MySQL中,join语句中的“ ON”和“ WHERE”之间有什么区别? and SQL join: where clause vs. on clause - it does matter if a condition is placed in the on-clause vs. the where-clause in an outer join. SQL加盟:where子句主场迎战一对条款 - 非常重要,如果条件放在上子句与在WHERE子句中的外部联接。

However, does it matter which on-clause the condition is placed in when there are multiple outer joins? 但是,当有多个外部联接时,条件放在哪个子句上是否重要?

For example, could these produce different results? 例如,这些会产生不同的结果吗?

select * from t1 left join t2 on t1.fid=t2.id and t2.col=val
                 left join t3 on t2.fid=t3.id;

vs: VS:

select * from t1 left join t2 on t1.fid=t2.id
                 left join t3 on t2.fid=t3.id and t2.col=val;

Absolutely they are different. 绝对是不同的。

The fisrt query will only have t2 rows that satisfy t2.col=val t2.col=val查询将仅包含满足t2t2.col=val

The second query will include all t2 rows and only list t3 when t2.col=val 第二个查询将包括所有t2行,并且仅当t2.col=val时列出t3

The queries are not equivalent. 查询不等效。 It is easy to construct a counter example: 构造一个反例很容易:

create table t1 (id int not null, val int not null);
create table t2 (id int not null, val int not null);
create table t3 (id int not null, val int not null);
insert into t1 (id, val) values (1,1);
insert into t2 (id, val) values (1,1);
insert into t3 (id, val) values (1,1);

select * from t1 
left join t2 
    on t1.id = t2.id 
    and t2.val = 2 
left join t3 
    on t2.id = t3.id;
+----+-----+------+------+------+------+
| id | val | id   | val  | id   | val  |
+----+-----+------+------+------+------+
|  1 |   1 | NULL | NULL | NULL | NULL |
+----+-----+------+------+------+------+

select * from t1 
left join t2 
    on t1.id = t2.id 
left join t3 
    on t2.id = t3.id 
    and t2.val = 2;
+----+-----+------+------+------+------+
| id | val | id   | val  | id   | val  |
+----+-----+------+------+------+------+
|  1 |   1 |    1 |    1 | NULL | NULL |
+----+-----+------+------+------+------+

This is one of the queries: 这是查询之一:

select *
from t1 left join
     t2
     on t1.fid = t2.id left join
     t3
     on t2.fid = t3.id and t2.col = val;

Yes, the results are different. 是的,结果不同。 If you were using inner join they would be the same, but the left join changes things -- because the join clause does not do any filtering of rows. 如果您使用inner join它们将是相同的,但是left join改变事情-因为join子句不会对行进行任何过滤。

I think the simplest explanation is that the join between t1 and t2 will include all rows from t1 as well as all matching rows from t2 -- even those where t2.col <> val . 我认为最简单的解释是t1t2之间的t2.col <> val将包括t1所有行以及t2所有匹配行-甚至包括那些t2.col <> val These remain in the result set, because the next left join does not filter them out. 这些保留在结果集中,因为下一个left join不会将它们过滤掉。

In fact, the condition t2.col = val in the second on clause does not affect which rows are in the result set. 实际上,第二个on子句中的条件t2.col = val不会影响结果集中的行。 If there is a match, then the row from t3 stays based on the first condition. 如果存在匹配项,则t3的行将基于第一个条件停留。 If there is no match, then the row from t3 is still in the result set -- but the t3 columns will be NULL . 如果没有匹配项,则t3的行仍在结果集中-但t3列将为NULL

In this version: 在此版本中:

select *
from t1 left join
     t2
     on t1.fid = t2.id  and t2.col = val left join
     t3
     on t2.fid = t3.id;

The first join gets all rows from t1 and only matching rows from t2 where t2.col = val . 第一个t2.col = valt1获得所有行,并且仅从t2获得匹配行,其中t2.col = val The third join can then add more rows. 然后,第三个联接可以添加更多行。

Note: there are definitely situations where the two queries would return the same results. 注意:在某些情况下,两个查询将返回相同的结果。 But, the following data would generate different results (assume val = 0): 但是,以下数据将产生不同的结果(假设val = 0):

t1 T1

fid
1

t2 T2

fid   col
1     0
1     1

t3 T3

id 
1

The query with the condition in the second on clause will return: 在第二个on子句中具有条件的查询将返回:

1    1    0    1
1    1    1    NULL

The query with the condition in the first on clause will return: 在第一个on子句中具有条件的查询将返回:

1    1    0    1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM