Today I received email from Yoel from Israel. He is one smart man always bringing up interesting questions. Let us see his latest email first.
Hi Pinal,
I am subscribed to your blog and enjoy reading it. I have a question which has been bothering me for some time now.
When I want to filter records in a query, I usually put the condition in the WHERE clause. When I make an inner join, I can put the condition in the ON clause instead, giving the same result. But with left joins this is not the case. Here is a quote from the SQL Server documentation:
Although the placement of such predicates does not make a difference for INNER joins, they might cause a different result when OUTER joins are involved. This is because the predicates in the ON clause are applied to the table before the join, whereas the WHERE clause is semantically applied to the result of the join.
I still can’t fully grasp the difference. Perhaps you could explain this better? I am sure that many of your readers could benefit from this too.
Thank you.
Yoel,
You have asked very good question. Let us go through following example first. Download the script for this example here and execute in SSMS. I will explain the behavior as we go through the example. If any user does not want to read complete explanation, just go last paragraph of article which is in bold fonts.
USE AdventureWorks
GO
-- Create Table1
CREATEÂ TABLE Table1
(ID INT, Value VARCHAR(10), Flag INT
)
GO
-- Populate Table1
INSERTÂ INTO Table1 (ID, Value, Flag)
SELECT 1, 'First', 1
UNION ALL
SELECT 2, 'Second', 1
UNION ALL
SELECT 3, 'Third', 2
UNION ALL
SELECT 4, 'Fourth', 1
UNION ALL
SELECT 5, 'Fifth', 2
UNION ALL
SELECT 6, 'Sixth', 1
UNION ALL
SELECT 7, 'Seventh', 2
GO
-- Create Table2
CREATEÂ TABLE Table2
(ID INT, Value VARCHAR(10), Flag INT
)
GO
-- Populate Table2
INSERTÂ INTO Table2 (ID, Value, Flag)
SELECT 1, 'First', 1
UNION ALL
SELECT 2, 'Second', 1
UNION ALL
SELECT 3, 'Third', 2
UNION ALL
SELECT 8, 'Eightth', 1
UNION ALL
SELECT 9, 'Nineth', 2
GO
-- Check the data in Table1 and Table2
SELECT *
FROM Table1
SELECT *
FROM Table2
GO
-- INNER JOIN with WHERE Condition
SELECT *
FROM Table1Â t1
INNERÂ JOIN Table2Â t2 ON t1.ID = t2.ID
WHERE t2.Flag = 1
GO
-- INNER JOIN with Additional Condition on ON clause
SELECT *
FROM Table1Â t1
INNERÂ JOIN Table2Â t2 ON t1.ID = t2.ID AND t2.Flag = 1
GO
-- LEFT JOIN with WHERE Condition
SELECT *
FROM Table1Â t1
LEFT JOIN Table2Â t2 ON t1.ID = t2.ID AND t2.Flag = 1
GO
-- LEFT JOIN with Additional Condition on ON clause
SELECT *
FROM Table1Â t1
LEFT JOIN Table2Â t2 ON t1.ID = t2.ID
WHERE t2.Flag = 1
GO
-- Clean up tables
DROPÂ TABLE Table1
DROPÂ TABLE Table2
GO
Let us see the example in parts. Let us see the result of INNER JOIN clause. First of all we will run the query without WHERE clause and ON clause. Our result of join without any clause has to be same as they are essentially same query.
Now we will run the same query with WHERE clause and ON clause and compare our result with earlier result and later resultset.
As mentioned earlier it really does not matter for INNER JOIN if WHERE condition is moved to ON clause. In case of JOIN if ON clause (evaluated first) of WHERE clause (evaluated later) the result is same.
Now let us see the example of LEFT JOIN. First we will run both the queries without WHERE clause and ON clause. Our result of join without any clause has to be same as they are essentially same query.
Now we will run the same query with WHERE clause and ON clause and compare our result with earlier result and later resultset.
Now let us understand ON clause it is apply before JOIN that is why it retrieves all the result of Table2 where there are Flag = 1 but it does not affect Table1 so it retrieves all the rows of table1. When WHERE clause is applied it applies to complete result so it removes all the rows from Table1 and Table2 where Flag is not equal to 1, essentially keeping flag = 1 rows from Table1 and Table2.
I hope now this explanation is clear to Yoel. I am really waiting for feedback from my readers about this article. If you think this is interesting article, please share it on your social network and leave your comment here.
Reference : Pinal Dave (https://blog.sqlauthority.com)
77 Comments. Leave new
if i want the result grouped by t2.Flag instead of passing it as default value then how to do?
for example
i have
tableA tableB
id student id data year
1 s1 1 d1 2010
2 s2 2 d2 2010
1 d3 2012
now if i join i want the result like
id student data year
1 s1 d1 2010
1 s1 d3 2010
2 s2 d2 2012
2 s2 NULL 2012
thanx pinal, i was also facing some problem like the above example ,thanx for your explanation it helped me.
As we see the result of inner join and left join with where clause are identical do we really need to use a left join here? Are they both not same?
If you want to apply the WHERE clause as shown in the post, it is better to use INNER JOIN
Sir.. good article. .clear explanation with very simple queries.
ravikiran, I am glad that you liked it.
Nice article Pinal & thank you for your clear & straight explanation !
Thanks ksathish1.
excellent explanation, now I understand this concept
Thanx a lot
You are welcome!
nice article
Thanks @Priyanka
Great post Pinal. Quick question: what would be difference between:
SELECT *
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.ID = t2.ID AND t2.Flag = 1
— LEFT JOIN with WHERE clause and OR IS NULL
SELECT *
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.ID = t2.ID
WHERE t2.Flag = 1 OR t2.Flag is null
It actually produced different results for me (I’m using AWS RedShift though)
Thank you,
Bruno
Both are not equal queries
Hi Pinal,
quick question. If On clause evaluate first it means that is going to be faster? since the join will use less data?
thanks
There is no proof of it.
Grate Help guys…appreciate a lot
Hi Pinal,
Firstly, thanks for a great explanation. I have a question related to this topic. Let’s say that the Flag = 1 condition is instead applicable on the left table T1 thus T1.Flag = 1 is added in the ON clause. My understanding was that since this condition is for the left table, only the records matching this condition would be selected from the left table (T1) for the JOIN however that’s not the case. Can you please provide some explanation on this?