I am getting different results based on a filter condition in a query based on where I place the filter condition. My questions are:
- Is there a technical difference between these queries?
- Is there anything in the SQL standard that explains the different recordsets from the queries?
Given the simplified scenario:
--Table: Parent Columns: ID, Name, Description
--Table: Child Columns: ID, ParentID, Name, Description
--Query 1
SELECT p.ID, p.Name, p.Description, c.ID, c.Name, c.Description
FROM Parent p
LEFT OUTER JOIN Child c ON (p.ID = c.ParentID)
WHERE c.ID IS NULL OR c.Description = 'FilterCondition'
--Query 2
SELECT p.ID, p.Name, p.Description, c.ID, c.Name, c.Description
FROM Parent p
LEFT OUTER JOIN Child c
ON (p.ID = c.ParentID AND c.Description = 'FilterCondition')
I assumed the queries would return the same resultsets and I was surprised when they didn't. I am using MS SQL2005 and in the actual queries, query 1 returned ~700 rows and query 2 returned ~1100 rows and I couldn't detect a pattern on which rows were returned and which rows were excluded. There were still many rows in query 1 with child rows with data and NULL data. I prefer the style of query 2 (and I think it is more optimal), but I thought the queries would return the same results.
Edit/Summary:
There were some great answers provided here. I had a hard time choosing to whom to award the answer. I decided to go with mdma since it was the first answer and one of the clearest. Based on the supplied answers, here is my summary:
Possible results:
- A: Parent with no children
- B: Parents with children
- |-> B1: Parents with children where no child matches the filter
- \-> B2: Parents with children where 1 or more match the filter
Query results:
- Query 1 returns (A, B2)
- Query 2 returns (A, B1, B2)
Query 2 always returns a parent because of the left join. In query 1, the WHERE clause is performed after the left join, so parents with children where none of the children match the filter are excluded (case B1).
Note: only parent information is returned in case B1, and in case B2 only the parent/child information matching the filter is returned.
HLGEM provided a good link:
http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN