Just be careful of the difference with outer joins
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);
Is not the same as
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE b.IsApproved = 1;
Since for 'failed' outer joins on Bar, b.IsApproved
will always be NULL
and hence filtered out.
Another way of looking at this is that for LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId)
, that the additional filter (b.IsApproved = 1)
will be ignored if the join (b.BarId = f.BarId)
fails, because LEFT/RIGHT OUTER JOIN guarantees the LEFT / RIGHT table rows will be retained even if the join fails.
Because of these pitfalls we have a rules in our organisation such as
- Use simple primary keys only (i.e. no composite keys) - i.e. 1:1 column joining
- Only JOIN should be used for join conditions, i.e. Don't join in the WHERE clause
- No additional FILTERS are permitted in the JOIN criteria
This should guarantee that INNER and OUTER joins are always of the form
FROM lhs INNER/LEFT JOIN rhs ON lhs.FK = rhs.PK
WHERE OtherFiltersHere
Which avoids a ton of issues. As others have pointed out, this improves readability as well.
Update:
To complete the question asked by Conrad, the equivalent LOJ for an OPTIONAL filter would be:
SELECT *
FROM Foo f
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE
(b.IsApproved IS NULL OR b.IsApproved = 1);
i.e. The WHERE clause needs to consider both the condition whether the join fails (NULL) and the filter is to be ignored, and where the join succeeds and the filter must be applied. (b.IsApproved
or b.BarId
could be tested for NULL)
WHERE
and join conditions in theON
. – KM. Apr 24 '12 at 11:58tableA.column = tableB.column
a filter condition istableA.Column=5
. When doing outer joins (LEFT/RIGHT) you must put the filter conditions within theON
or code yourWHERE
in this manner(tableA.Column=5 OR tableA.Column IS NULL)
– KM. Apr 24 '12 at 18:07