Web Analytics Made Easy - Statcounter
Home » SQL Server » SQL JOIN Cheat Sheet: INNER, LEFT, RIGHT, FULL, CROSS JOIN, NULLs & Performance

SQL JOIN Cheat Sheet: INNER, LEFT, RIGHT, FULL, CROSS JOIN, NULLs & Performance

Sql Join Cheat Sheet Inner Left Right Full Cross Join Nulls Performance
SQL JOIN Cheat Sheet: INNER, LEFT, RIGHT, FULL, CROSS JOIN, NULLs & Performance

Introduction

SQL JOINs are one of the most important concepts when working with relational databases. They allow us to combine related data from multiple tables.

But understanding JOIN syntax is only the beginning. In real-world SQL Server development and troubleshooting, you also need to understand NULL behavior, ON vs WHERE conditions, result-set multiplication, indexes, and execution plans.

This cheat sheet covers the most commonly used SQL JOINs along with practical NULL and performance considerations.

Sample Tables

Let’s use the following tables throughout the examples.

Customers

CustomerIDCustomerName
1Amit
2Priya
3Rahul
4Neha

Orders

OrderIDCustomerIDAmount
1011500
1021700
1032300
1045900

Notice two important things:

  • Customers 3 and 4 don’t have orders.
  • Order 104 has CustomerID 5, but customer 5 doesn’t exist in the Customers table.

For the CROSS JOIN example, we’ll also use:

Products

ProductIDProductName
1Laptop
2Mouse
3Keyboard

These examples make it easier to understand exactly how different JOINs behave.

SQL JOIN Cheat Sheet

JOIN TypeWhat it returnsTypical use
INNER JOINOnly matching rowsFind customers who have orders
LEFT JOINAll rows from left + matching rows from rightFind all customers, including those without orders
RIGHT JOINAll rows from right + matching rows from leftFind all orders, including unmatched orders
FULL OUTER JOINAll matching and unmatched rows from both tablesCompare two datasets
CROSS JOINEvery possible combinationGenerate combinations

1. INNER JOIN

An INNER JOIN returns only rows that have a match in both tables.

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Customers AS c
INNER JOIN Orders AS o
    ON c.CustomerID = o.CustomerID;

Complete Result

CustomerIDCustomerNameOrderIDAmount
1Amit101500
1Amit102700
2Priya103300

Rahul and Neha are excluded because they don’t have matching orders.

Order 104 is also excluded because CustomerID 5 doesn’t exist in Customers.

Visual rule

Customers                 Orders

Amit       ─────────────── Order 101
Amit       ─────────────── Order 102
Priya      ─────────────── Order 103

Rahul      ✕
Neha       ✕

Order 104  ✕

Remember:

INNER JOIN = Matching rows only

2. LEFT JOIN

A LEFT JOIN returns all rows from the left table and matching rows from the right table.

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Customers AS c
LEFT JOIN Orders AS o
    ON c.CustomerID = o.CustomerID;

Complete Result

CustomerIDCustomerNameOrderIDAmount
1Amit101500
1Amit102700
2Priya103300
3RahulNULLNULL
4NehaNULLNULL

Rahul and Neha remain in the result because Customers is the left table.

Because they have no matching order, the columns coming from Orders are NULL.

Notice that Order 104 is not returned because the unmatched row exists on the right side.

Remember:

LEFT JOIN = Everything from left + matching rows from right

3. RIGHT JOIN

A RIGHT JOIN is the reverse of a LEFT JOIN.

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.CustomerID AS OrderCustomerID,
    o.Amount
FROM Customers AS c
RIGHT JOIN Orders AS o
    ON c.CustomerID = o.CustomerID;

Complete Result

CustomerIDCustomerNameOrderIDOrderCustomerIDAmount
1Amit1011500
1Amit1021700
2Priya1032300
NULLNULL1045900

Order 104 remains because Orders is the right table.

Because there is no matching customer, the columns coming from Customers become NULL.

In practice, many developers prefer rewriting a RIGHT JOIN as a LEFT JOIN because it is often easier to read:

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Orders AS o
LEFT JOIN Customers AS c
    ON o.CustomerID = c.CustomerID;

Remember:

RIGHT JOIN = Everything from right + matching rows from left

4. FULL OUTER JOIN

A FULL OUTER JOIN returns:

  • Matching rows
  • Unmatched rows from the left table
  • Unmatched rows from the right table
SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.CustomerID AS OrderCustomerID,
    o.Amount
FROM Customers AS c
FULL OUTER JOIN Orders AS o
    ON c.CustomerID = o.CustomerID;

Complete Result

CustomerIDCustomerNameOrderIDOrderCustomerIDAmount
1Amit1011500
1Amit1021700
2Priya1032300
3RahulNULLNULLNULL
4NehaNULLNULLNULL
NULLNULL1045900

This result shows everything from both tables.

  • Rahul and Neha have no matching order.
  • Order 104 has no matching customer.
  • Amit and Priya have matching rows.

Where do NULLs come from?

For Rahul and Neha:

Orders columns → NULL

For Order 104:

Customers columns → NULL

Remember:

FULL OUTER JOIN = Everything from both tables

5. CROSS JOIN

A CROSS JOIN produces every possible combination of rows.

SELECT
    c.CustomerID,
    c.CustomerName,
    p.ProductID,
    p.ProductName
FROM Customers AS c
CROSS JOIN Products AS p;

We have:

4 Customers × 3 Products = 12 combinations

Complete Result

CustomerIDCustomerNameProductIDProductName
1Amit1Laptop
1Amit2Mouse
1Amit3Keyboard
2Priya1Laptop
2Priya2Mouse
2Priya3Keyboard
3Rahul1Laptop
3Rahul2Mouse
3Rahul3Keyboard
4Neha1Laptop
4Neha2Mouse
4Neha3Keyboard

A CROSS JOIN can be useful for generating combinations, test data, scenarios, or reporting dimensions.

However, it can produce a very large result set very quickly.

For example:

100 customers × 20 products = 2,000 rows

Remember:

CROSS JOIN = Every possible combination

SQL JOIN Result Comparison

Using our sample data, here’s the easiest way to compare the JOIN types:

JOINRows returnedKey behavior
INNER JOIN3Only matching customer/order rows
LEFT JOIN5All 4 customers + matching orders
RIGHT JOIN4All 4 orders + matching customers
FULL OUTER JOIN6Everything from both sides
CROSS JOIN124 customers × 3 products

This table is useful as a quick reference when deciding which JOIN you need.

SQL JOIN and NULL Behavior

NULL behavior is one of the most commonly misunderstood parts of SQL JOINs.

Suppose a customer doesn’t have an order:

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Customers AS c
LEFT JOIN Orders AS o
    ON c.CustomerID = o.CustomerID;

Complete Result

CustomerIDCustomerNameOrderIDAmount
1Amit101500
1Amit102700
2Priya103300
3RahulNULLNULL
4NehaNULLNULL

The NULL values for Rahul and Neha don’t mean that SQL Server found an actual NULL order.

They mean:

No matching row was found in the right-side table.

This distinction is important.

Finding Records Without a Match

A very common requirement is finding customers who have never placed an order.

SELECT
    c.CustomerID,
    c.CustomerName
FROM Customers AS c
LEFT JOIN Orders AS o
    ON c.CustomerID = o.CustomerID
WHERE o.CustomerID IS NULL;

Complete Result

CustomerIDCustomerName
3Rahul
4Neha

This is commonly called an anti-join pattern.

The same requirement can often be expressed using NOT EXISTS:

SELECT
    c.CustomerID,
    c.CustomerName
FROM Customers AS c
WHERE NOT EXISTS
(
    SELECT 1
    FROM Orders AS o
    WHERE o.CustomerID = c.CustomerID
);

Result

CustomerIDCustomerName
3Rahul
4Neha

Both approaches can be useful. When performance matters, compare the actual execution plans rather than assuming one approach is always faster.

Finding Orders Without a Matching Customer

We can reverse the logic to find orphaned orders.

SELECT
    o.OrderID,
    o.CustomerID,
    o.Amount
FROM Orders AS o
LEFT JOIN Customers AS c
    ON o.CustomerID = c.CustomerID
WHERE c.CustomerID IS NULL;

Complete Result

OrderIDCustomerIDAmount
1045900

This tells us that Order 104 references CustomerID 5, but CustomerID 5 does not exist in the Customers table.

This type of query is useful when looking for orphaned or inconsistent data.

Important: NULL Does Not Equal NULL

A common mistake is writing:

WHERE SomeColumn = NULL

This does not work as expected.

Use:

WHERE SomeColumn IS NULL

or:

WHERE SomeColumn IS NOT NULL

SQL uses three-valued logic:

TRUE
FALSE
UNKNOWN

Therefore:

NULL = NULL

does not evaluate to TRUE.

For JOIN conditions, this means that a normal equality condition does not match two NULL values:

ON a.SomeColumn = b.SomeColumn

If both columns contain NULL, that comparison does not produce a TRUE result.

ON vs WHERE with OUTER JOINs

This is one of the most important JOIN concepts to understand.

Consider:

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Customers AS c
LEFT JOIN Orders AS o
    ON c.CustomerID = o.CustomerID
WHERE o.Amount > 500;

The WHERE condition removes rows where o.Amount is NULL.

Complete Result

CustomerIDCustomerNameOrderIDAmount
1Amit102700

Although we started with a LEFT JOIN, the WHERE condition removes Rahul and Neha because their o.Amount is NULL.

Now compare that with:

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Customers AS c
LEFT JOIN Orders AS o
    ON c.CustomerID = o.CustomerID
   AND o.Amount > 500;

Complete Result

CustomerIDCustomerNameOrderIDAmount
1Amit102700
2PriyaNULLNULL
3RahulNULLNULL
4NehaNULLNULL

The difference is important.

The condition in the ON clause controls which right-side rows can match, while the WHERE clause filters the final result.

Practical Rule

When using OUTER JOINs, always ask:

Should this condition affect matching, or should it filter the final result?

Moving a predicate between ON and WHERE can change the result set significantly.

JOIN Performance: What Should You Watch?

A common misconception is:

“INNER JOIN is faster than LEFT JOIN.”

There is no universal rule like this.

SQL Server chooses an execution strategy based on factors such as:

  • Table size
  • Indexes
  • Statistics
  • Data distribution
  • Join predicates
  • Cardinality estimates
  • Available memory
  • Query predicates
  • Required output
  • Execution plan

The important question isn’t simply:

Which JOIN is faster?

Instead ask:

Why did SQL Server choose this execution plan for this JOIN?

1. Indexes on JOIN Columns

Suppose we frequently execute:

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount
FROM Orders AS o
JOIN Customers AS c
    ON o.CustomerID = c.CustomerID;

An appropriate index on the JOIN column can help SQL Server locate matching rows efficiently.

For example:

CREATE INDEX IX_Orders_CustomerID
ON Orders(CustomerID);

However, don’t blindly create an index for every JOIN column.

Index design should consider:

  • Query workload
  • Selectivity
  • Existing indexes
  • Read/write balance
  • Included columns
  • Storage
  • Actual execution plans

2. Data Type Mismatch

Be careful when joining columns with incompatible data types.

For example:

ON o.CustomerID = c.CustomerCode

where one column is an integer and the other is a character column.

SQL Server may need to perform an implicit conversion.

Check the execution plan and column definitions when investigating unexpected JOIN performance.

Prefer compatible data types for related keys.

3. Functions on JOIN Columns

Avoid unnecessary expressions on columns used for joining.

For example:

ON CAST(o.CustomerID AS VARCHAR(20)) = c.CustomerCode

Expressions such as this can make efficient index access more difficult, depending on the query and data types involved.

Prefer compatible data types and straightforward predicates where possible.

4. Large Intermediate Result Sets

A JOIN can produce far more rows than expected.

For example:

1 customer
      ↓
10 matching orders
      ↓
10 result rows

Now consider a many-to-many relationship:

100 rows
   ×
200 matching rows
   =
20,000 possible combinations

This is why understanding table relationships is important.

Before joining tables, determine whether the relationship is:

1 : 1
1 : Many
Many : Many

Many-to-many JOINs deserve particular attention because they can create unexpectedly large intermediate result sets.

5. SELECT Only the Columns You Need

Avoid:

SELECT *

when you don’t need every column.

Prefer:

SELECT
    c.CustomerID,
    c.CustomerName,
    o.OrderID,
    o.Amount

Returning only required columns can reduce the amount of data SQL Server needs to read, process, and return.

It can also make it easier to design useful covering indexes where appropriate.

SQL Server JOIN Execution Plan Operators

SQL Server can use different physical operators to implement a logical JOIN.

The three operators you will commonly encounter are:

Join OperatorCommon scenario
Nested LoopsOften useful when one input is relatively small and the other can be accessed efficiently
Hash MatchOften useful for larger unsorted inputs
Merge JoinOften effective when inputs are appropriately sorted on the join keys

There is no universally “best” JOIN operator.

For example, seeing a Hash Match in an execution plan does not automatically mean there is a problem.

When analyzing a JOIN, look at:

  • Estimated vs actual rows
  • Table and index scans
  • Key lookups
  • Memory grants
  • Hash spills
  • Sort operations
  • Predicate selectivity
  • Missing or inappropriate indexes
  • Statistics
  • Overall query cost and execution time

Common JOIN Mistakes

1) Forgetting the JOIN condition

Be careful with:

FROM Customers AS c
JOIN Orders AS o

An unintended Cartesian product can produce a huge number of rows.

Always verify the JOIN predicate.

2) Using DISTINCT to Hide Duplicate Results

If a JOIN produces unexpected duplicates, don’t immediately add:

SELECT DISTINCT

Let understand why the JOIN is producing multiple rows.

The underlying issue may be:

  • A one-to-many relationship
  • A many-to-many relationship
  • An incomplete JOIN condition
  • Duplicate data
  • An incorrect business relationship

3) Filtering an OUTER JOIN Incorrectly

A condition in the WHERE clause can unintentionally remove NULL-extended rows created by an OUTER JOIN.

Always check whether the condition belongs in ON or WHERE.

4) Ignoring Table Relationships

Before joining tables, understand whether the relationship is:

1 : 1
1 : Many
Many : Many

This can dramatically affect the number of rows returned.

Quick SQL JOIN Decision Guide

Need only matching records?

INNER JOIN

Need all records from the main/left table?

LEFT JOIN

Need all records from the right table?

RIGHT JOIN

Need everything from both tables?

FULL OUTER JOIN

Need every possible combination?

CROSS JOIN

Need records that don’t have a match?

LEFT JOIN ... WHERE right_table.key IS NULL

or:

NOT EXISTS

SQL JOIN One-Line Cheat Sheet

INNER JOIN  → Matching rows only

LEFT JOIN   → All left rows + matching right rows

RIGHT JOIN  → All right rows + matching left rows

FULL JOIN   → All rows from both tables

CROSS JOIN  → Every possible combination

Complete JOIN Comparison at a Glance

Using our sample Customers and Orders tables:

CustomerCustomerIDOrderOrder CustomerIDINNERLEFTRIGHTFULL
Amit11011✓✓✓✓
Amit11021✓✓✓✓
Priya21032✓✓✓✓
Rahul3——✗✓✗✓
Neha4——✗✓✗✓
——1045✗✗✓✓

This is perhaps the most important visual to remember:

INNER → Keep matches

LEFT  → Keep everything on the left

RIGHT → Keep everything on the right

FULL  → Keep everything on both sides

Final SQL JOIN Checklist

Before using a JOIN in a production query, ask:

  • What rows must always appear?
  • Is this a 1:1, 1:many, or many:many relationship?
  • Can the JOIN create duplicate or unexpected rows?
  • How should unmatched rows be handled?
  • Could NULL values affect the result?
  • Should a filter be in ON or WHERE?
  • Are the JOIN columns using compatible data types?
  • Are appropriate indexes available?
  • Are statistics current enough for the workload?
  • What does the actual execution plan show?
  • Is SQL Server processing significantly more rows than expected?

Interview Questions On SQL Joins

Summary

A SQL JOIN is more than a piece of syntax.

The real skill is understanding which rows should be returned, how unmatched rows and NULLs behave, how JOIN conditions affect the result, and how SQL Server executes the JOIN.

Once you understand these concepts, JOINs become much easier to write, troubleshoot, and optimize.

Remember:

Choose the JOIN based on the result you need, then use the execution plan to understand its performance.


Discover more from Technology with Vivek Johari

Subscribe to get the latest posts sent to your email.

Leave a Reply

Scroll to Top

Discover more from Technology with Vivek Johari

Subscribe now to keep reading and get access to the full archive.

Continue reading