MySQL Left Join не возвращает нулевые значения для объединенной таблицы
Пожалуйста, помогите мне со следующим 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?
Ответы
Ответ 1
Вы не должны указывать 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)
Ответ 2
Грег, это действительно все, что есть в запросе?
Примеры таблиц
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
.
Подумайте о LEFT JOIN, как это [1]
SELECT * from A
left join B on A.sid = B.sid
Храните все в и, если они совпадают в предложении 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, как показано ниже, в противном случае это может сделать его INNER JOIN.
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)