Problem
I am new to Microsoft SQL Server and want to learn about the JOIN options for the relational database. What are all of the JOIN options in SQL Server? What is the significance of each of the options? I am a little confused on the differences and syntax, can you provide some examples and explanations? Are JOINs only for SELECT statements? Check out this SQL Tutorial to learn about SQL Server Join Types and example syntax.
Solution
Joining tables to obtain the needed data for a query, script or stored procedure is a key concept as you learn about SQL Server development. In a nutshell, joins are typically performed in the FROM clause of a table or view for the SELECT, INSERT…SELECT, SELECT…INTO, UPDATE and DELETE statements. In previous versions of SQL Server, join logic could also have been included in the WHERE clause with = (INNER JOIN), *= (LEFT OUTER JOIN), =* (RIGHT OUTER JOIN), etc. syntax, but the support has been reduced and the best practice in SQL Server is to use the syntax outlined in the examples below.
Types of Joins in SQL Server
Before we jump into code, let’s provide some baseline information on the types of JOINs in SQL Server:
SQL INNER JOIN match rows between the two tables specified in the INNER JOIN statement based on one or more columns having matching data – Equi Join. Preferably the join is based on referential integrity enforcing the relationship between the tables to ensure data integrity.
With a SQL LEFT OUTER JOIN based on the two tables specified in the join clause, all data is returned from the left table. On the right table, the matching data is returned in addition to NULL values where a record exists in the left table, but not in the right table.
Another item to keep in mind is that the LEFT and RIGHT OUTER JOIN logic is opposite of one another. So, you can change either the order of the tables in the specific join statement or change the JOIN from left to right or vice versa and get the same results.
Based on the two tables specified in the join clause, with a SQL RIGHT OUTER JOIN all data is returned from the right table. On the left table, the matching data is returned in addition to NULL values where a record exists in the right table but not in the left table.
In this circumstance, the same table is specified twice with two different aliases in order to match the data within the same table.
Based on the two tables specified in the join clause, a Cartesian product is created if a WHERE clause does filter the rows. The size of the Cartesian product is based on multiplying the number of rows from the left table by the number of rows in the right table. Please heed caution when using a CROSS JOIN.
Based on the two tables specified in the join clause, all data is returned from both tables regardless of matching data.
Let’s walk through examples from the AdventureWorks sample database that is available for SQL Server to provide example SQL statements for each type of JOIN then provide some insight into the usage and sample result sets.
SQL Server INNER JOIN Example
In the following query we have a SQL INNER JOIN clause between the Sales.SalesOrderDetail and Production.Product tables. The tables are aliased with the following:
- SOD for Sales.SalesOrderDetail
- P for Production.Product.
The JOIN condition is based on matching rows in the SOD.ProductID and P.ProductID columns.
The records are filtered by only returning records with the SOD.UnitPrice (column name) greater than 1000.
Finally, the result set is returned in order with the most expensive first based on the ORDER BY clause and only the highest 100 products based on the TOP clause.
SELECT TOP 100
P.ProductID,
P.Name,
P.ListPrice,
P.Size,
P.ModifiedDate,
SOD.UnitPrice,
SOD.UnitPriceDiscount,
SOD.OrderQty,
SOD.LineTotal
FROM Sales.SalesOrderDetail SOD
INNER JOIN Production.Product P ON SOD.ProductID = P.ProductID
WHERE SOD.UnitPrice > 1000
ORDER BY SOD.UnitPrice DESCSQL Server LEFT OUTER JOIN Example
In the following query we are combining two concepts to show that more than two tables can be JOINed in one SELECT statement and more than one JOIN type can be used in a single SELECT statement.
In the sample code below, we are retrieving the matching rows between the Person.Contact and Sales.SalesPerson tables in conjunction with all of the data from the Sales.SalesPerson table and matching rows in the Sales.SalesTerritory table.
For records that exist Sales.SalesPerson table and not in the Sales.SalesTerritory table, NULL values are returned for the columns in the Sales.SalesTerritory.
In addition, this code uses two columns to order the data i.e. ST.TerritoryID and C.LastName.
SELECT
C.ContactID,
C.FirstName,
C.LastName,
SP.SalesPersonID,
SP.CommissionPct,
SP.SalesYTD,
SP.SalesLastYear,
SP.Bonus,
ST.TerritoryID,
ST.Name,
ST.[Group],
ST.SalesYTD
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP ON C.ContactID = SP.SalesPersonID
LEFT OUTER JOIN Sales.SalesTerritory ST ON ST.TerritoryID = SP.TerritoryID
ORDER BY ST.TerritoryID, C.LastNameSQL Server RIGHT OUTER JOIN Example
In an effort to explain how the RIGHT OUTER JOIN and LEFT OUTER JOIN is logically a reciprocal on one another, the following query is re-written version of the LEFT OUTER JOIN above.
As you can see the JOIN order and tables are different, but the final result set matches the LEFT OUTER JOIN logic.
In the sample code below, we are retrieving the matching rows between the Person.Contact and Sales.SalesPerson tables in conjunction with all of the data from the Sales.SalesPerson table and matching rows in the Sales.SalesTerritory table.
For records that exist Sales.SalesPerson table and not in the Sales.SalesTerritory table, NULL values are returned for the columns in the Sales.SalesTerritory.
SELECT
C.ContactID,
C.FirstName,
C.LastName,
SP.SalesPersonID,
SP.CommissionPct,
SP.SalesYTD,
SP.SalesLastYear,
SP.Bonus,
ST.TerritoryID,
ST.Name, ST.[Group],
ST.SalesYTD
FROM Sales.SalesTerritory ST
RIGHT OUTER JOIN Sales.SalesPerson SP ON ST.TerritoryID = SP.TerritoryID
INNER JOIN Person.Contact C ON C.ContactID = SP.SalesPersonID
ORDER BY ST.TerritoryID, C.LastNameSQL Server Self Join Example
In this example, we are actually self-joining to the HumanResources.Employee table. We are doing this to obtain the information about the Employee and Manager relationship in the HumanResources.Employee table.
In conjunction with that JOIN logic we are also joining to the Person.Contact twice in order to capture the name and title data based on the original Employee and Manager relationships.
In addition, another new concept introduced in this query is aliasing each of the column names.
Although we could have done so in the previous examples, we made point of doing so in this query to differentiate between the Employee and Manager related data.
SELECT
M.ManagerID AS 'ManagerID',
M1.ContactID AS 'ManagerContactID',
M1.FirstName AS 'ManagerFirstName',
M1.LastName AS 'ManagerLastName',
M.Title AS 'ManagerTitle',
E.EmployeeID AS 'EmployeeID',
E1.ContactID AS 'EmployeeContactID',
E1.FirstName AS 'EmployeeFirstName',
E1.LastName AS 'EmployeeLastName',
E.Title AS 'EmployeeTitle'
FROM HumanResources.Employee E
INNER JOIN HumanResources.Employee M ON E.ManagerID = M.EmployeeID
INNER JOIN Person.Contact E1 ON E1.ContactID = E.ContactID
INNER JOIN Person.Contact M1 ON M1.ContactID = M.ContactID
ORDER BY M1.LastNameSQL Server CROSS JOIN Example
As indicated above, please heed caution when running or modifying this query in any SQL Server database environment. The result set is intentionally limited by the TOP 100 clause and the WHERE clause to prevent a Cartesian product, which is the result of each of the rows from the left table multiplied by the number of rows in the right table.
SELECT TOP 100
P.ProductID,
P.Name,
P.ListPrice,
P.Size,
P.ModifiedDate,
SOD.UnitPrice,
SOD.UnitPriceDiscount,
SOD.OrderQty,
SOD.LineTotal
FROM Sales.SalesOrderDetail SOD
CROSS JOIN Production.Product P
WHERE SOD.UnitPrice > 3500
ORDER BY SOD.UnitPrice DESCSQL Server FULL OUTER JOIN Example
In our last example, we have modified the logic from the LEFT OUTER JOIN example above and converted the LEFT OUTER JOIN syntax to a FULL OUTER JOIN.
In this circumstance, the result set is the same as the LEFT OUTER JOIN where we are returning all of the data between both tables and data not available in the Sales.SalesTerritory is returned as NULL.
SELECT
C.ContactID,
C.FirstName,
C.LastName,
SP.SalesPersonID,
SP.CommissionPct,
SP.SalesYTD,
SP.SalesLastYear,
SP.Bonus,
ST.TerritoryID,
ST.Name,
ST.[Group],
ST.SalesYTD
FROM Person.Contact C
INNER JOIN Sales.SalesPerson SP ON C.ContactID = SP.SalesPersonID
FULL OUTER JOIN Sales.SalesTerritory ST ON ST.TerritoryID = SP.TerritoryID
ORDER BY ST.TerritoryID, C.LastNameKey Takeaways
- SQL Server Join Types include INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, SELF JOIN, CROSS JOIN, and FULL OUTER JOIN.
- Each JOIN type serves a specific purpose and retrieves data based on different criteria between tables.
- Examples illustrate the syntax and application of each JOIN type in queries, including SELECT, INSERT, UPDATE, and DELETE statements.
- Understanding SQL Server Join Types is essential for effective data retrieval and manipulation within SQL Server development.
- Explore alternatives to JOINs such as UNION, INTERSECT, and EXCEPT for more advanced data operations.
Next Steps
As you begin to start coding in SQL Server be sure to have a firm understanding of the JOIN options available as well as the associated data that is retrieved. Be sure to select the correct JOIN logic based on the data that needs to be retrieved.
Once you have a firm grasp of the JOIN logic with SELECT statements, progress to using the logic with INSERT…SELECT, SELECT…INTO, UPDATE and DELETE statements
In your learning process progresses, be sure to check out some of the alternatives to JOINs such as:
- Joining data and differences of using UNION and UNION ALL in SQL Server
- Comparing Multiple SQL Server Datasets with the INTERSECT and EXCEPT operators
Check out the related MSSQLTips articles:
- SQL Server SELECT Tutorial
- SQL Server Stored Procedure
- SQL Server Cursor Examples
- Getting started with SQL Server stored procedures
- SQL Server SELECT Examples
- SQL SELECT DISTINCT Examples
- Using MERGE in SQL Server to insert, update and delete at the same time
- SQL INSERT INTO SELECT Examples
- SQL UPDATE Statement
- SQL Update Statement with Join in SQL Server vs Oracle vs PostgreSQL
- The T-SQL DELETE statement
- Delete SQL Statement in SQL Server, Oracle and PostgreSQL

Jeremy Kadlec is a Founder, Editor and Author at MSSQLTips.com with more than 300 contributions and 25+ years of SQL Server experience. Jeremy leads a team of more than 300 authors helping millions of SQL Server professionals around the globe every second of the day for the last 20 years. He is also the CTO @ Edgewood Solutions and a six-time SQL Server MVP based on his community contributions. Jeremy brings 25+ years of SQL Server DBA and Developer knowledge to the community and holds a bachelor’s degree from SSU and master’s degree from UMBC.
David,
Can you please provide a bit more insight into your question with some sample data and what the final output should be?
Thank you,
Jeremy Kadlec
How can I join overlapping data from two different tables? I have an Event: E1 @ T1 and Event: E2 @ T2. I’m trying to correlate the state model when T2 happens. When I use an outer join the data is there but it doesn’t correlate correctly.
From the first table: E1 happens @ T1= 2/12/2021 0:44 with event = running
From the second table: E2 happens @ 2/12/2021 7:50 with event = OOS