MySQL Left Join не возвращает нулевые значения для объединенной таблицы - PullRequest
21 голосов
/ 25 марта 2011

Пожалуйста, помогите мне со следующим запросом MySQL, который объединяет две таблицы (A и B):

SELECT * from A
left join B on A.sid = B.sid
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
AND (rYear = 2011 or rYear is null)

roleCode - это поле в таблице A, а rYear - это поле в таблице B

.

Набор результатов не такой, как ожидалось. Возвращается только 185 строк, но в таблице A есть 629 строк, которые соответствуют условию where. Разве строки без соответствующей строки в таблице B не должны возвращаться с нулевыми значениями для их полей B?

Ответы [ 2 ]

51 голосов
/ 25 марта 2011

Вы не должны указывать rYear в предложении WHERE. Те ограничивают ваши результаты после объединения. Вы должны указать rYear в предложении ON для получения записей с NULL из таблицы B.

SELECT * from A
left join B 
on A.sid = B.sid 
AND (rYear = 2011 or rYear is null)
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
1 голос
/ 25 марта 2011

Грег, это действительно все, что нужно для запроса?

Образцы таблиц

create table A(rCode int, sid int);
insert A select 1,1;
insert A select 2,3;
insert A select 3,2;
insert A select 5,4;
insert A select 1,5;
create table B(rYear int, sid int);
insert B select 2011,1;
insert B select null,3;
insert B select 2011,2;
insert B select 2015,2;

Запросы:

SELECT * from A
left join B on A.sid = B.sid
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
AND (rYear = 2011 or rYear is null);

SELECT * from A
left join B on A.sid = B.sid AND (rYear = 2011 or rYear is null)
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5);

Оба запроса одинаковы, оба возвращают:

rCode       sid         rYear       sid
----------- ----------- ----------- -----------
1           1           2011        1
2           3           NULL        3
3           2           2011        2
5           4           NULL        NULL
1           5           NULL        NULL

Поэтому я удивлен, что запрос Jage (второй вариант) работает для вас, но не для вашего оригинала. Это была бы другая история без внутреннего or rYear is null.

Думайте о левом соединении, как это [1]

SELECT * from A
left join B on A.sid = B.sid

Сохраняйте все в A, а в случае совпадения в предложении ON сохраняйте B, в противном случае столбцы B заполняйте NULL. Добавьте предложение WHERE [2]

where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
AND (rYear = 2011 or rYear is null);

Используя выход из [1], CUT вниз на основе фильтра, примененного ПОСЛЕ левого соединения. С rYear is null он все равно должен хранить все записи A, при условии, что фильтр rCode совпадает. Однако, если фильтр в rYear только

AND (rYear in (2011,2012))

Это другая история, потому что там, где B не был сопоставлен, rYear был дополнен значением NULL, что не будет соответствовать фильтру rYear -> удаляется вся строка, включая запись A. Такой фильтр для rYear мог бы войти в предложение ON, как показано ниже, в противном случае это также может сделать его ВНУТРЕННИМ СОЕДИНЕНИЕМ.

SELECT * from A
left join B on A.sid = B.sid AND (rYear in (2011,2012))
where (rCode = 1 Or rCode = 2 Or rCode = 3 Or rCode = 5)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...