MySQL размещение условий в on-предложениях нескольких внешних объединений
Как продолжение в SQL / MySQL, в чем разница между "ON" и "WHERE" в операторе соединения? и SQL join: предложение where против предложения on - имеет значение, помещается ли условие в предложение on вместо предложения where во внешнем соединении.
Однако имеет ли значение, в какое условие on помещается условие, когда существует несколько внешних объединений?
Например, могут ли они дать разные результаты?
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;
3 ответа
Абсолютно они разные.
Первый запрос будет иметь только t2
строки, которые удовлетворяют t2.col=val
Второй запрос будет включать все t2
строки и только список t3
когда t2.col=val
Запросы не эквивалентны. Легко построить контрпример:
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 |
+----+-----+------+------+------+------+
Это один из запросов:
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
не отфильтровывает их.
На самом деле, состояние t2.col = val
во-вторых on
Предложение не влияет на то, какие строки находятся в наборе результатов. Если есть совпадение, то строка из 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