MySQL 在多个外部连接的子句中放置条件
Posted
技术标签:
【中文标题】MySQL 在多个外部连接的子句中放置条件【英文标题】:MySQL placement of conditions in on-clauses of multiple outer joins 【发布时间】:2015-02-25 03:06:16 【问题描述】:作为 In SQL / mysql, what is the difference between "ON" and "WHERE" in a join statement? 和 SQL join: where clause vs. on clause 的后续行动 - 将条件放在 on 子句与外连接中的 where 子句之间确实很重要。
但是,当有多个外连接时,哪个子句放置条件是否重要?
例如,这些会产生不同的结果吗?
select * from t1 left join t2 on t1.fid=t2.id and t2.col=val
left join t3 on t2.fid=t3.id;
对比:
select * from t1 left join t2 on t1.fid=t2.id
left join t3 on t2.fid=t3.id and t2.col=val;
【问题讨论】:
val
: 那是什么? t1.val
还是别的什么?
【参考方案1】:
它们绝对不同。
第一个查询将只有满足t2.col=val
的t2
行
第二个查询将包括所有t2
行,并且仅在t2.col=val
时列出t3
【讨论】:
太好了,谢谢@Jasen。我的想法是,如果你想过滤最左边的表(和上) - 使用“where”,下一个表 - 使用最左边的“on”,然后是下一个“on”,等等所以过滤的顺序是:where, on #1, on #2 ... 是的,通常where
只提到起始表,如果您使用where
中其他表的列,则通常意味着该表的列上的is not null
将left join
变为一个inner join
。【参考方案2】:
查询不等价。反例很容易构建:
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 |
+----+-----+------+------+------+------+
【讨论】:
【参考方案3】:这是查询之一:
select *
from t1 left join
t2
on t1.fid = t2.id left join
t3
on t2.fid = t3.id and t2.col = val;
是的,结果不同。如果您使用的是inner join
,它们将是相同的,但left join
改变了一些东西——因为join
子句不会对行进行任何过滤。
我认为最简单的解释是t1
和t2
之间的连接将包括来自t1
的所有行以及来自t2
的所有匹配行——甚至包括t2.col <> val
的那些行。这些保留在结果集中,因为下一个 left join
不会将它们过滤掉。
实际上,第二个on
子句中的条件t2.col = val
不会影响结果集中的哪些行。如果存在匹配项,则来自t3
的行将基于第一个条件。如果没有匹配项,则来自t3
的行仍在结果集中——但t3
列将是NULL
。
在这个版本中:
select *
from t1 left join
t2
on t1.fid = t2.id and t2.col = val left join
t3
on t2.fid = t3.id;
第一个连接从t1
获取所有行,并且仅从t2
获取匹配行,其中t2.col = val
。然后第三个连接可以添加更多行。
注意:在某些情况下,两个查询肯定会返回相同的结果。但是,以下数据会产生不同的结果(假设 val = 0):
t1
fid
1
t2
fid col
1 0
1 1
t3
id
1
第二个on
子句中带有条件的查询将返回:
1 1 0 1
1 1 1 NULL
第一个on
子句中的条件查询将返回:
1 1 0 1
【讨论】:
以上是关于MySQL 在多个外部连接的子句中放置条件的主要内容,如果未能解决你的问题,请参考以下文章