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
Другие вопросы по тегам