Просто внимавайте за разликата с външните съединения. Заявка, където филтър на b.IsApproved
(в дясната таблица, Bar) се добавя към ON
условие на JOIN
:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);
Е НЕ същото като поставянето на филтъра в WHERE
клауза:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved = 1);
Тъй като за 'неуспешни' външни присъединявания към Bar
(т.е. където няма b.BarId
за f.BarId
), това ще остави b.IsApproved
като NULL
за всички такива неуспешни редове за присъединяване и тези редове след това ще бъдат филтрирани.
Друг начин да разгледаме това е, че за първата заявка LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId)
винаги ще връща ЛЯВИТЕ редове на таблицата, тъй като LEFT OUTER JOIN
гарантира, че ЛЯВИТЕ редове на таблицата ще бъдат върнати, дори ако присъединяването е неуспешно. Въпреки това, ефектът от добавянето на (b.IsApproved = 1)
към LEFT OUTER JOIN
условието е да се нулират всички десни колони на таблицата, когато (b.IsApproved = 1)
е невярно, т.е. съгласно същите правила, които обикновено се прилагат към LEFT JOIN
условие на (b.BarId = f.BarId)
.
Актуализиране :За да завършите въпроса, зададен от Конрад, еквивалентният LOJ за НЕЗАПЪЛНИТЕЛЕН филтър би бил:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);
т.е. WHERE
клаузата трябва да вземе предвид и двете условия дали присъединяването е неуспешно (NULL)
и филтърът трябва да се игнорира, а когато свързването е успешно и филтърът трябва да се приложи. (b.IsApproved
или b.BarId
може да бъде тестван за NULL
)
Тук съставих SqlFiddle, който демонстрира разликите между различните разположения на b.IsApproved
филтър спрямо JOIN
.