DP-900Chapter 21 of 101Objective 2.3

SQL Joins: INNER, LEFT, RIGHT, FULL

This chapter covers SQL joins — the mechanism for combining rows from two or more tables based on a related column. Joins are fundamental to relational database queries and appear on roughly 15-20% of DP-900 exam questions, especially in the context of querying Azure SQL Database, Azure Synapse, and other relational data stores. Mastering the semantics of INNER, LEFT, RIGHT, and FULL joins is essential for writing correct queries and understanding how relational data is retrieved in Azure data services.

25 min read
Intermediate
Updated May 31, 2026

SQL Joins Like Filing Cabinet Cross-References

Imagine two filing cabinets in an office: Cabinet A holds employee records (EmployeeID, Name, DepartmentID), and Cabinet B holds department records (DepartmentID, DeptName). Each record in Cabinet A has a DepartmentID that points to a record in Cabinet B. An INNER JOIN is like taking only the employee records that have a matching department record and stapling them together — if an employee has a DepartmentID that doesn't exist in Cabinet B, that employee is ignored. A LEFT JOIN is like taking all employee records (left side) and, for each, looking up the department; if no match exists, you attach a blank sticky note for department info. A RIGHT JOIN is the opposite: start with all department records, attach employee info where available, and leave blanks for unmatched departments. A FULL JOIN is like dumping both cabinets on a table and matching whatever you can; unmatched records from either side appear with blanks. The key mechanistic detail: the 'drive side' (LEFT or RIGHT) determines which set is preserved entirely; the other side only contributes matches. In SQL, the join condition is evaluated row by row: for each row in the left table, the database engine probes an index or scans the right table for matching rows. If multiple matches exist, all combinations are produced (this is a Cartesian product within the join). Understanding this row-by-row matching is critical for predicting result sets.

How It Actually Works

What Are SQL Joins and Why Do They Exist?

In relational databases, data is normalized into multiple tables to reduce redundancy and improve integrity. For example, a sales database might have separate tables for Customers, Orders, and Products. To answer questions like "list all customers with their order totals," you must combine rows from these tables. SQL joins provide the mechanism to combine rows from two or more tables based on a related column (typically a foreign key). The DP-900 exam expects you to understand the four fundamental join types: INNER, LEFT OUTER, RIGHT OUTER, and FULL OUTER. (The keyword OUTER is optional and often omitted.)

How Joins Work Internally: The Row-by-Row Mechanism

When a SQL query with a join executes, the database engine follows a logical processing order. First, it identifies the source tables and applies any filters (WHERE clause) that can be pushed down. Then, for each row in the first table (often called the left table or driving table), the engine looks up matching rows in the second table (right table) based on the join condition specified in the ON clause. The join condition is usually an equality comparison, like Orders.CustomerID = Customers.CustomerID.

INNER JOIN: Only rows that have at least one match in both tables are returned. If a row in the left table has no match in the right table, it is excluded. Similarly, rows in the right table with no match are excluded. The result set contains every combination of matching rows — if one left row matches three right rows, three result rows are produced.

LEFT JOIN (or LEFT OUTER JOIN): All rows from the left table are preserved. For rows that have no match in the right table, the right table columns are filled with NULL. If a left row matches multiple right rows, multiple result rows are generated (with non-NULL right columns).

RIGHT JOIN (or RIGHT OUTER JOIN): The mirror of LEFT JOIN. All rows from the right table are preserved; unmatched left rows produce NULLs for left table columns.

FULL JOIN (or FULL OUTER JOIN): Both tables are preserved. Rows from either side that have no match produce NULLs for the opposite table's columns. This is equivalent to the union of a LEFT JOIN and a RIGHT JOIN (without duplicates).

Key Components: Join Condition, ON Clause, and NULL Handling

The join condition is specified in the ON clause. It can involve multiple columns (compound join) and can use operators other than equality (non-equi joins), though the DP-900 exam focuses on equi-joins. When a join produces NULLs for unmatched rows, those NULLs can affect subsequent filtering. For example, if you write:

SELECT *
FROM Customers C
LEFT JOIN Orders O ON C.CustomerID = O.CustomerID
WHERE O.OrderDate = '2023-01-01'

This effectively turns the LEFT JOIN into an INNER JOIN because the WHERE clause filters out rows where O.OrderDate is NULL (unmatched customers). To preserve all customers, move the condition to the ON clause:

SELECT *
FROM Customers C
LEFT JOIN Orders O ON C.CustomerID = O.CustomerID AND O.OrderDate = '2023-01-01'

This nuance is frequently tested on the DP-900 exam.

Configuration and Verification in Azure Data Services

In Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics dedicated SQL pools, joins are used in T-SQL queries. There is no special configuration for joins — they are part of the SQL language. However, performance depends on indexes. For large tables, an index on the join column(s) can dramatically speed up the lookup. You can verify the execution plan using:

SET SHOWPLAN_XML ON;
GO
SELECT ... FROM ... JOIN ...;
GO
SET SHOWPLAN_XML OFF;

In Azure Synapse Serverless SQL pool, joins work similarly but with distributed query processing. The DP-900 exam does not require deep knowledge of execution plans, but you should understand that joins can be expensive and that indexing is important.

Interaction with Related Technologies

Azure Cosmos DB (NoSQL): Does not support SQL joins in the same way; instead, you use subqueries or client-side joins. The DP-900 exam tests that relational joins are not available in Cosmos DB's SQL API.

Azure Data Lake Storage / Azure Blob Storage: Data stored as files; you would use PolyBase or Azure Synapse to join data across files using external tables. The join syntax remains T-SQL.

Azure Stream Analytics: Uses temporal joins (e.g., JOIN with DATEDIFF) for streaming data, but the concept of INNER/LEFT joins applies.

Common Mistakes and Exam Traps

Mixing LEFT JOIN and WHERE: As shown above, placing a condition on the right table in the WHERE clause can eliminate unmatched rows. The exam loves to test this.

Forgetting that multiple matches cause row multiplication: A LEFT JOIN with a one-to-many relationship returns more rows than the left table alone.

Confusing RIGHT JOIN with LEFT JOIN: RIGHT JOIN is rarely used in practice, but the exam tests its semantics. Think of it as "preserve the right table."

Assuming FULL JOIN is the same as UNION: A FULL JOIN preserves both sides, but it combines columns horizontally; UNION combines rows vertically.

Using Set Theory to Understand Joins

Visualize two sets: A (left table rows) and B (right table rows). The join condition defines a relationship. - INNER JOIN = A ∩ B (intersection) - LEFT JOIN = A ∪ (A ∩ B) — all of A, plus the intersection (but since intersection is already part of A, it's just A with B's attributes where they match) - FULL JOIN = A ∪ B (union)

This set analogy helps but is imperfect because the join can produce multiple rows from a single left row.

Performance Considerations

Nested Loops Join: For small tables or when one table is indexed. The engine iterates over each row of the outer table and probes the inner table.

Hash Join: For larger tables with no indexes. Builds a hash table on the smaller table, then scans the larger table to find matches.

Merge Join: For sorted inputs. Both tables are sorted on the join key, and then they are merged. Often the fastest.

The DP-900 exam does not require you to choose a join algorithm, but you should know that joins can be resource-intensive and that indexing helps.

Summary of Join Behaviors

| Join Type | Left Table Rows | Right Table Rows | NULLs from Right | NULLs from Left | |-----------|----------------|-----------------|------------------|-----------------| | INNER | Only matched | Only matched | No | No | | LEFT | All | Only matched | Yes for unmatched| No | | RIGHT | Only matched | All | No | Yes for unmatched| | FULL | All | All | Yes for unmatched| Yes for unmatched|

This table is exam gold. Memorize it.

Example Queries

Assume tables:

CREATE TABLE Employees (EmpID INT, Name VARCHAR(50), DeptID INT);
CREATE TABLE Departments (DeptID INT, DeptName VARCHAR(50));

Sample data:

Employees: (1, 'Alice', 10), (2, 'Bob', 20), (3, 'Charlie', NULL) Departments: (10, 'Sales'), (20, 'Marketing'), (30, 'HR')

INNER JOIN:

SELECT E.Name, D.DeptName
FROM Employees E
INNER JOIN Departments D ON E.DeptID = D.DeptID;

Result: Alice-Sales, Bob-Marketing. Charlie is excluded (DeptID is NULL, no match). HR is excluded (no employee).

LEFT JOIN:

SELECT E.Name, D.DeptName
FROM Employees E
LEFT JOIN Departments D ON E.DeptID = D.DeptID;

Result: Alice-Sales, Bob-Marketing, Charlie-NULL. Charlie preserved with NULL for DeptName.

RIGHT JOIN:

SELECT E.Name, D.DeptName
FROM Employees E
RIGHT JOIN Departments D ON E.DeptID = D.DeptID;

Result: Alice-Sales, Bob-Marketing, NULL-HR. HR preserved with NULL for Name.

FULL JOIN:

SELECT E.Name, D.DeptName
FROM Employees E
FULL JOIN Departments D ON E.DeptID = D.DeptID;

Result: Alice-Sales, Bob-Marketing, Charlie-NULL, NULL-HR. All rows from both tables appear.

Cross Join (Cartesian Product)

Not a join type commonly tested in DP-900, but worth noting: CROSS JOIN produces every combination of rows from both tables. It has no ON clause. For example, 3 employees × 3 departments = 9 rows. This is rarely used in practice but can appear in exam questions about join fundamentals.

Self-Join

A table can be joined to itself. This is used for hierarchical data (e.g., employees and managers). The syntax is the same, but table aliases are essential. For example:

SELECT E1.Name AS Employee, E2.Name AS Manager
FROM Employees E1
LEFT JOIN Employees E2 ON E1.ManagerID = E2.EmpID;

This is a common pattern for reporting structures.

Join with Multiple Tables

You can join more than two tables. The order of joins matters logically but not performance-wise (the optimizer reorders). Example:

SELECT C.CustomerName, O.OrderDate, P.ProductName
FROM Customers C
INNER JOIN Orders O ON C.CustomerID = O.CustomerID
INNER JOIN OrderDetails OD ON O.OrderID = OD.OrderID
INNER JOIN Products P ON OD.ProductID = P.ProductID;

This returns only customers who have placed orders with details.

The Importance of NULL in Joins

NULL is not a value; it represents missing data. In join comparisons, NULL = NULL is not true (it yields UNKNOWN). Therefore, rows with NULL in the join column will never match any row, even if the other table has NULL. This is why Charlie (DeptID = NULL) does not match Department 30 (DeptID = 30) — they are not equal, and NULL is not equal to anything. This is a common exam trap.

Exam Objective Code: 2.3

This objective covers querying relational data in Azure. You should be able to write and interpret queries that use joins. The exam may present a scenario and ask which join type produces the desired result. It may also ask about the number of rows returned or the presence of NULLs.

Conclusion

Mastering joins requires understanding the set preservation rules and the effect of NULLs. Practice writing queries with sample data to see the results. The DP-900 exam will test your ability to choose the correct join type based on a business requirement. Remember: LEFT preserves left, RIGHT preserves right, INNER keeps only matches, FULL keeps everything.

Walk-Through

1

1. Identify the Tables and Join Condition

Determine which two tables need to be combined and the column(s) that relate them. For example, in a query joining Orders and Customers, the common column is CustomerID. Write the ON clause specifying the equality: `ON Orders.CustomerID = Customers.CustomerID`. Ensure the data types match; otherwise, implicit conversion may occur, affecting performance and correctness.

2

2. Choose the Join Type Based on Requirements

Decide whether you need all rows from one or both tables. If you need only matching rows, use INNER JOIN. If you need all rows from the first table (left) regardless of matches, use LEFT JOIN. If you need all rows from the second table (right), use RIGHT JOIN. If you need all rows from both tables, use FULL JOIN. The DP-900 exam often gives a business requirement: 'List all customers, even if they have no orders' → LEFT JOIN (Customers left, Orders right).

3

3. Write the SELECT Statement with the JOIN

Start with `SELECT` and list columns, prefixing with table aliases for clarity (e.g., `C.CustomerName, O.OrderID`). Then `FROM` the left table with an alias. Then the join keyword (`INNER JOIN`, `LEFT JOIN`, etc.) followed by the right table and its alias. Then `ON` with the join condition. Optionally add `WHERE`, `GROUP BY`, `ORDER BY`. Example: `SELECT C.CustomerName, O.OrderID FROM Customers C LEFT JOIN Orders O ON C.CustomerID = O.CustomerID;`

4

4. Execute and Verify the Result Set

Run the query in a tool like Azure Data Studio or SSMS. Check the number of rows returned. For a LEFT JOIN, the row count should be at least the number of rows in the left table (more if there are multiple matches). Verify that unmatched rows contain NULLs in the right table columns. For INNER JOIN, the row count should be less than or equal to the number of left rows. If the result seems off, examine the data for unexpected NULLs or duplicate matches.

5

5. Optimize with Indexes if Needed

For large tables, ensure there is an index on the join column(s) in both tables, especially the 'inner' table in a nested loops join. In Azure SQL Database, you can create indexes using `CREATE INDEX IX_Orders_CustomerID ON Orders(CustomerID);`. Use the execution plan to identify table scans. The DP-900 exam does not require index tuning, but understanding that joins benefit from indexes is important.

What This Looks Like on the Job

Enterprise Scenario 1: Customer Order Reporting in a Retail Company

A retail company uses Azure SQL Database to store customer and order data. The marketing team needs a report of all customers and their total order amounts, including customers who have never placed an order. The naive query uses INNER JOIN:

SELECT C.CustomerID, C.CustomerName, SUM(O.OrderAmount) AS TotalSpent
FROM Customers C
INNER JOIN Orders O ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID, C.CustomerName;

This returns only customers with orders, missing new or inactive customers. The correct query uses LEFT JOIN:

SELECT C.CustomerID, C.CustomerName, COALESCE(SUM(O.OrderAmount), 0) AS TotalSpent
FROM Customers C
LEFT JOIN Orders O ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID, C.CustomerName;

COALESCE replaces NULL with 0. In production, this query runs daily against millions of rows. Without an index on Orders.CustomerID, the join performs a full table scan, taking minutes. Adding a nonclustered index reduces it to seconds. Misconfiguration (e.g., missing index) leads to timeout errors and frustrated business users.

Enterprise Scenario 2: HR Employee-Department Directory

A multinational corporation uses Azure Synapse Analytics for HR data. They need a complete list of all employees and their department names, including employees not yet assigned to a department (DeptID is NULL) and departments with no employees. This requires a FULL JOIN:

SELECT E.EmployeeName, D.DepartmentName
FROM Employees E
FULL JOIN Departments D ON E.DeptID = D.DeptID;

In a data warehouse with billions of rows, FULL JOIN can be extremely expensive because it requires preserving both sides and handling NULLs. Often, the business requirement can be satisfied with a LEFT JOIN plus a separate query for empty departments, then UNION. Misusing FULL JOIN unnecessarily can cause query timeouts and resource contention. The data engineering team must evaluate whether the full outer join is truly needed.

Enterprise Scenario 3: E-Commerce Product Inventory

An e-commerce platform uses Azure SQL Database to track products and inventory. The reporting team needs to list all products and their current stock quantity, including products that have never been stocked (no inventory record). This is a LEFT JOIN from Products to Inventory. However, a common mistake is to filter on inventory columns in the WHERE clause:

SELECT P.ProductID, P.ProductName, I.Quantity
FROM Products P
LEFT JOIN Inventory I ON P.ProductID = I.ProductID
WHERE I.Quantity > 0;

This eliminates products with NULL quantity (unstocked products), turning the join into an INNER JOIN. The correct approach is to move the condition to the ON clause or use a subquery. In production, this error led to a report that omitted new products, causing inventory managers to believe they had no new items to order. The fix was to change the WHERE to WHERE (I.Quantity > 0 OR I.Quantity IS NULL) or to use ON P.ProductID = I.ProductID AND I.Quantity > 0.

How DP-900 Actually Tests This

DP-900 Exam Focus on SQL Joins (Objective 2.3)

The DP-900 exam tests your ability to:

Identify the correct join type for a given business requirement.

Predict the result set (number of rows, presence of NULLs).

Understand the impact of WHERE clause conditions on outer joins.

Recognize that NULLs do not match in join conditions.

Common Wrong Answers and Why Candidates Choose Them

1.

Using INNER JOIN when LEFT JOIN is required: Candidates see "list all customers" and assume INNER JOIN, forgetting that customers without orders should be included. The exam will phrase "all customers, regardless of whether they have placed an order" — the word "all" signals LEFT JOIN.

2.

Confusing LEFT and RIGHT JOIN: Candidates transpose the tables. For example, if the requirement is "list all departments, even if they have no employees," the correct join is RIGHT JOIN if Departments is on the right, or LEFT JOIN if Departments is on the left. The exam often presents the tables in a specific order in the FROM clause, so you must pay attention.

3.

Thinking FULL JOIN returns exactly the number of rows in the larger table: Actually, FULL JOIN returns all rows from both tables, with NULLs for non-matching sides. If a row in the left table matches multiple rows in the right table, multiple rows appear. The row count can exceed the sum of both tables.

4.

Assuming WHERE clause on the right table preserves outer join behavior: Placing a condition on the right table's column in WHERE (e.g., WHERE Orders.OrderDate IS NOT NULL) filters out unmatched rows, effectively converting an outer join to an inner join. Candidates often don't realize this.

Specific Numbers, Values, and Terms

The keyword OUTER is optional: LEFT JOIN is same as LEFT OUTER JOIN.

The join condition is specified with ON, not USING (though USING exists, it's not tested).

NULL is not equal to NULL; comparisons involving NULL yield UNKNOWN.

The default join type if you write JOIN without INNER is INNER JOIN.

Edge Cases and Exceptions

Self-join: Joining a table to itself requires aliases. The exam may test that you need different aliases.

Cross join: No ON clause; produces Cartesian product. Rare but can appear.

Multiple joins: The order of joins matters logically; the exam may ask which join type to use first.

Join with aggregate functions: When using GROUP BY with a LEFT JOIN, unmatched rows produce NULL aggregates; use COALESCE to replace with 0.

How to Eliminate Wrong Answers

1.

Read the requirement carefully: Look for keywords like "all", "regardless", "even if no match".

2.

Determine which table is the 'driving' table (the one whose rows must all appear).

3.

If the driving table is the first table in FROM, use LEFT JOIN. If the second, use RIGHT JOIN. If both, use FULL JOIN. If only matches, use INNER JOIN.

4.

Check if the WHERE clause references the right table — if so, it may filter out unmatched rows.

5.

Count rows: INNER JOIN ≤ left rows; LEFT JOIN ≥ left rows; FULL JOIN ≥ max(left, right) rows.

Master these patterns, and you will answer join questions correctly.

Key Takeaways

INNER JOIN returns only rows with matching values in both tables; unmatched rows are excluded.

LEFT JOIN returns all rows from the left table; unmatched rows show NULLs for right table columns.

RIGHT JOIN returns all rows from the right table; unmatched rows show NULLs for left table columns.

FULL JOIN returns all rows from both tables; unmatched rows show NULLs for the opposite table.

NULL does not match any value, including another NULL, in a join condition.

A WHERE clause condition on the right table's column can turn an outer join into an inner join.

Multiple matches cause row multiplication: one left row matching three right rows produces three result rows.

The keyword OUTER is optional (e.g., LEFT JOIN = LEFT OUTER JOIN).

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

INNER JOIN

Returns only rows with matches in both tables.

Unmatched rows from either table are excluded.

Result set row count ≤ number of rows in left table (if no duplicates).

No NULLs from either side for matched rows.

Used when you only need data that exists in both tables.

LEFT JOIN

Returns all rows from the left table, matched or unmatched.

Unmatched right table columns are NULL.

Result set row count ≥ number of rows in left table.

NULLs appear in right table columns for unmatched left rows.

Used when you need all rows from the left table regardless of matches.

Watch Out for These

Mistake

LEFT JOIN and RIGHT JOIN are interchangeable by swapping the order of tables in the FROM clause.

Correct

Technically true: `SELECT * FROM A LEFT JOIN B` is equivalent to `SELECT * FROM B RIGHT JOIN A`. However, the DP-900 exam expects you to understand the semantics based on the given query. Swapping tables changes the 'left' and 'right' roles. Always evaluate which table is preserved.

Mistake

NULL matches NULL in a join condition.

Correct

NULL = NULL evaluates to UNKNOWN, not TRUE. Therefore, two rows with NULL in the join column will never match. This is a common exam trap. For example, if both tables have a NULL foreign key, they do not join.

Mistake

A FULL JOIN returns the union of the two tables (all rows from both, no duplicates).

Correct

FULL JOIN returns all rows from both tables, but if a row from the left table matches multiple rows from the right table, multiple result rows are produced. It is not a set union; it is a join that preserves all rows from both sides, with NULLs for non-matches. The number of rows can exceed the sum of both tables.

Mistake

Adding a WHERE clause on the right table column does not affect the number of rows returned by a LEFT JOIN.

Correct

If the WHERE clause filters on a column from the right table (e.g., `WHERE Orders.OrderID IS NOT NULL`), it removes rows where the right table columns are NULL, i.e., the unmatched left rows. This effectively converts the LEFT JOIN into an INNER JOIN. To preserve unmatched rows, move the condition to the ON clause.

Mistake

INNER JOIN returns all rows from both tables.

Correct

INNER JOIN returns only rows that have at least one match in the other table. Rows from either table that have no match are excluded. This is the opposite of FULL JOIN.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

What is the difference between INNER JOIN and LEFT JOIN?

INNER JOIN returns only rows that have matching values in both tables. If a row in the left table has no match in the right table, it is excluded. LEFT JOIN returns all rows from the left table; if there is no match, the right table columns are filled with NULL. For example, if you want all customers and their orders, LEFT JOIN ensures customers with no orders still appear.

How do I remember which table is preserved in LEFT JOIN vs RIGHT JOIN?

Think of the direction: LEFT JOIN preserves the left table (the one after FROM). RIGHT JOIN preserves the right table (the one after the JOIN keyword). A common mnemonic: 'LEFT keeps left, RIGHT keeps right.' If you are confused, you can always rewrite a RIGHT JOIN as a LEFT JOIN by swapping the table order in the FROM clause.

Why does my LEFT JOIN return fewer rows than expected?

This often happens because you have a WHERE clause that filters on a column from the right table. For example, `WHERE Orders.OrderDate = '2023-01-01'` removes rows where Orders columns are NULL (unmatched left rows). To fix, move the condition to the ON clause: `LEFT JOIN Orders ON ... AND Orders.OrderDate = '2023-01-01'`.

Can a FULL JOIN produce more rows than the sum of both tables?

Yes. If a row in the left table matches multiple rows in the right table, multiple result rows are generated. For example, if Table A has 1 row and Table B has 3 matching rows, the FULL JOIN produces 3 rows (not 1+3=4). The row count can be greater than the sum if there are multiple matches.

What happens if the join column contains NULLs?

Rows with NULL in the join column will not match any row in the other table, because NULL = NULL is not true (it evaluates to UNKNOWN). In an INNER JOIN, those rows are excluded. In a LEFT JOIN, they are preserved with NULLs for the right table columns. In a FULL JOIN, they appear with NULLs on the opposite side.

What is a self-join and when would I use it?

A self-join is when a table is joined to itself. It is used for hierarchical data, such as an Employees table with a ManagerID column that references the EmpID of the same table. You must use table aliases to distinguish the two roles. Example: `SELECT E1.Name AS Employee, E2.Name AS Manager FROM Employees E1 LEFT JOIN Employees E2 ON E1.ManagerID = E2.EmpID`.

How do joins affect query performance in Azure SQL Database?

Joins can be resource-intensive, especially on large tables without indexes. The database engine chooses a physical join operator (nested loops, hash match, merge join) based on statistics and indexes. To optimize, create indexes on the join columns. In Azure SQL Database, you can use the Query Performance Insight to identify slow joins. The DP-900 exam does not require deep performance tuning, but you should know that indexes help.

Terms Worth Knowing

Ready to put this to the test?

You've just covered SQL Joins: INNER, LEFT, RIGHT, FULL — now see how well it sticks with free DP-900 practice questions. Full explanations included, no account needed.

Done with this chapter?