Skip to main content

SQL Server JOIN basics


Yesterday I took an interview of an EXPERIENCED candidate. I was quite shocked to see the information he has on JOINs. Thus I thought about blogging about the basics of JOINs.
The scenario I gave him was -
CREATE TABLE #JOIN1
(
    ID INT,
    [TEXT] VARCHAR(100)
)
CREATE TABLE #JOIN2
(
    ID INT,
    [TEXT] VARCHAR(100)
)
INSERT INTO #JOIN1 VALUES(1,'TEXT JOIN 1 - 1')
INSERT INTO #JOIN1 VALUES(2,'TEXT JOIN 1 - 2')
INSERT INTO #JOIN1 VALUES(3,'TEXT JOIN 1 - 3')
INSERT INTO #JOIN1 VALUES(1,'TEXT JOIN 1 - 4')
INSERT INTO #JOIN1 VALUES(NULL,'TEXT JOIN 1 - 5')
INSERT INTO #JOIN2 VALUES(1,'TEXT JOIN 2 - 1')
INSERT INTO #JOIN2 VALUES(2,'TEXT JOIN 2 - 2')
INSERT INTO #JOIN2 VALUES(4,'TEXT JOIN 2 - 3')
INSERT INTO #JOIN2 VALUES(NULL,'TEXT JOIN 2 - 4')
INSERT INTO #JOIN2 VALUES(5,'TEXT JOIN 2 - 5')
Note: There is no primary key column.
Left Outer Join
MSDN defines a left outer join as - The Left Outer Join logical operator returns each row that satisfies the join of the first (top) input with the second (bottom) input. It also returns any rows from the first input that had no matching rows in the second input. The nonmatching rows in the second input are returned as null values. If no join predicate exists in the Argument column, each row is a matching row.
This is quite state forward for the guys with some experience but not that match for someone who is just trying his hands on JOINs.
Query -
SELECT * FROM #JOIN1 F
LEFT JOIN #JOIN2 S ON F.ID = S.ID
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 1 - 1 1 TEXT JOIN 2 - 1
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 2
3 TEXT JOIN 1 - 3 NULL NULL
1 TEXT JOIN 1 - 4 1 TEXT JOIN 2 - 1
NULL TEXT JOIN 1 - 5 NULL NULL
Id 1 is present in #JOIN1 and in #Join2 thus we have a matching record.
Id 2 is present in #JOIN1 and in #Join2 thus we have a matching record.
Id 3 is present in #JOIN1 and NOT in #Join2 thus we do not have a matching record. Thus we will get NULL for the row from #JOIN2 in the record set.
Id 1 is present in #JOIN1 and in #Join2 thus we have a matching record. (Duplicate ID)
Id NULL is present in #JOIN1 and in #Join2 BUT NULL is not equal to NULL and thus no matching record.
What you may I assume from above discussion
Correct Assumptions
If the join condition evaluates to be true then there will be a record from both tables.
All the records will come from LEFT table in the result set.
NULL is not equal to NULL and thus there can never be a match.
If the LEFT table has duplicates (ID – 1 in above case) they will be evaluated independently from each other. (That is why we had two separate records from in above set for ID – 1)
Incorrect Assumptions
The LEFT table will define the number of records in the result set. The truth is that it is the Joining condition which defines the number of records in the result set.
To prove this  insert one more record in #JOIN 2.
INSERT INTO #JOIN2 VALUES(2,'TEXT JOIN 2 - 6')
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 1 - 1 1 TEXT JOIN 2 - 1
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 2
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 6
3 TEXT JOIN 1 - 3 NULL NULL
1 TEXT JOIN 1 - 4 1 TEXT JOIN 2 - 1
NULL TEXT JOIN 1 - 5 NULL NULL
See the number of records and difference in text in #JOIN2 records in result set.
Right Outer Join
In case of RIGHT outer join the definition remains the same as the left outer join except that all the records from right table will be present in the result set.  NULL will be there in the result set for the records of left table where the join condition has failed.
SELECT * FROM #JOIN1 F
RIGHT JOIN #JOIN2 S ON F.ID = S.ID
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 1 - 1 1 TEXT JOIN 2 - 1
1 TEXT JOIN 1 - 4 1 TEXT JOIN 2 - 1
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 2
NULL NULL 4 TEXT JOIN 2 - 3
NULL NULL NULL TEXT JOIN 2 - 4
NULL NULL 5 TEXT JOIN 2 - 5
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 – 6
The explanation remains the same as in case of LEFT Outer Join and why not see the result set of this query -
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 2 - 1 1 TEXT JOIN 1 - 1
1 TEXT JOIN 2 - 1 1 TEXT JOIN 1 - 4
2 TEXT JOIN 2 - 2 2 TEXT JOIN 1 - 2
4 TEXT JOIN 2 - 3 NULL NULL
NULL TEXT JOIN 2 - 4 NULL NULL
5 TEXT JOIN 2 - 5 NULL NULL
2 TEXT JOIN 2 - 6 2 TEXT JOIN 1 – 2
Are not the same Smile.

INNER JOIN
Inner join is just like a where. It returns only those records for which join condition matches.
SELECT * FROM #JOIN1 F
INNER JOIN #JOIN2 S ON F.ID = S.ID
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 1 - 1 1 TEXT JOIN 2 - 1
1 TEXT JOIN 1 - 4 1 TEXT JOIN 2 - 1
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 2
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 – 6
To make it clearer let us tweak the join condition a bit.

SELECT * FROM #JOIN1 F
INNER JOIN #JOIN2 S ON F.ID = S.ID AND F.ID IN (1,3)
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 1 - 1 1 TEXT JOIN 2 - 1
1 TEXT JOIN 1 - 4 1 TEXT JOIN 2 – 1

Full Outer Join
Conceptually, a full outer join combines the effect of applying both left and right outer joins. Where records in the FULL OUTER JOINed tables do not match, the result set will have NULL values for every column of the table that lacks a matching row. For those records that do match, a single row will be produced in the result set (containing fields populated from both tables).
SELECT * FROM #JOIN1 F
FULL OUTER JOIN #JOIN2 S ON F.ID = S.ID
ID table #JOIN1 Text Table #JOIN1 ID table #JOIN1 Text Table #JOIN1
1 TEXT JOIN 1 - 1 1 TEXT JOIN 2 - 1
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 2
2 TEXT JOIN 1 - 2 2 TEXT JOIN 2 - 6
3 TEXT JOIN 1 - 3 NULL NULL
1 TEXT JOIN 1 - 4 1 TEXT JOIN 2 - 1
NULL TEXT JOIN 1 - 5 NULL NULL
NULL NULL 4 TEXT JOIN 2 - 3
NULL NULL NULL TEXT JOIN 2 - 4
NULL NULL 5 TEXT JOIN 2 – 5
In the next article of this series we will look into Cross Join, Self Join, Equi Join and usage in detail. We will also cover on the fly tables.

A book worth reading on SQL SERVER -

Comments

Popular posts from this blog

Laravel XAMPP MySQL artisan migrate install error mysql.sock

In my previous post I wrote about setting up Laravel 4 on Mac with XAMPP . When I tried to use migrations (using artisan) I faced some issue. I will also post about Laravel migrations soon.    php artisan migrate:install Error :                                                     [PDOException]                                       SQLSTATE[HY000] [2002] No such file or directory                                              Solution : We need to tell artisan which mysql we want it to use. For this to work we need to porivde it with mysql.sock which we want it to use. So change your database settings like this: 'mysql' => array( 'driver'    => 'mysql', 'host'      => 'localhost',     'unix_socket' => '/Applications/xampp/xamppfiles/var/mysql/mysql.sock', 'database'  => 'wedding', 'username'  => 'root', 'password'  => '', '

Add (Drop) a new article (table) at publisher in merge replication

Let us add the article using the GUI first. First of all create the table on publisher database. Now right click on the publisher and select properties from the menu. Click on articles. Uncheck the - "Show only checked articles in the list" checkbox, in order to see the newly added table. Select the table as shown in the figure below. Press ok The article has now been added to the publisher We now need to recreate the snapshot Right click the publication and select – “View snapshot agent status”. Click start to regenerate snapshot. Now right click on the subscription (I have both on same server you may have on different servers) and select “View synchronization status” Click on start on the agent. The schema changes will propagate to the client if you have "Replicate schema changes" property set to true in the publisher.

Check SQL Server Job status (State) using sp_help_job and xp_sqlagent_enum_jobs

This article is about checking the status of a SQL job. In our work place we have lot of SQL jobs. These jobs will run whole day and are business critical. They will load the data and generate extracts which will be used by business people. Thus, it becomes quite essential to support the system efficiently so that the job finishes in time and as desired. Also, while designing a new system sometimes we need to check the dependency of one job over another. In such scenario we need to check whether a particular job has finished or not. All this can be achieved in SQL Server by using the procedures:- sp_help_job xp_sqlagent_enum_jobs Note: xp_sqlagent_enum_jobs is an undocumented proc inside of sp_help_job and is used extensively to get SQL agent job information. sp_help_job: This procedure gives some insight into the status, and information, about a job. This stored procedure provides information such as last start time, job status etc. Syntax sp_help_job { [ @job_id= ] jo