TABLEAU • CONNECTING TO DATA

Joins — Create joins and choose join types (inner/left/right/full) (intro-to-standard)

Master the mechanics of combining relational tables in Tableau to unlock multi-source analytics.

Historical Context & Motivation

The concept of a join predates modern business intelligence tools by decades. At its core, a join is a relational algebra operation that combines rows from two or more tables based on a related column between them. Edgar F. Codd's seminal 1970 paper on the relational model established the theoretical groundwork for how data stored in separate, normalized tables could be recombined at query time to answer complex questions. Without joins, analysts would be forced to store everything in a single denormalized table — an approach that introduces massive redundancy, update anomalies, and storage inefficiency.

Tableau Desktop, first released in 2003, was designed to democratize data analysis by providing a visual, drag-and-drop interface. From the outset, its data connection layer needed to support the same relational join semantics that SQL programmers relied upon, but in a graphical, intuitive environment. Understanding how Tableau implements inner, left, right, and full outer joins is essential for any analyst who works with data distributed across multiple tables — which is nearly every real-world dataset.

1970
Codd's Relational Model
Edgar F. Codd publishes "A Relational Model of Data for Large Shared Data Banks," formalizing the algebra behind joins, projections, and selections that all modern databases — and Tableau — rely upon.
1986
SQL Standardization
ANSI SQL-86 standardizes JOIN syntax (INNER JOIN, LEFT OUTER JOIN, etc.), giving every relational database — and later every BI tool — a common vocabulary for combining tables.
2003
Tableau Desktop Launches
Tableau introduces a visual data connection pane where users can drag tables onto a canvas, create joins graphically, and choose join types from a dropdown — no SQL writing required.
2020
Relationships vs. Joins
Tableau 2020.2 introduces the logical layer (Relationships), but physical-layer joins remain indispensable for fine-grained control over how rows are matched before analysis begins.

The central question this lesson addresses is straightforward yet critical: when you have two or more tables that share a key, which join type should you choose, and what are the consequences of choosing incorrectly? Answering this question requires understanding both the theory of relational joins and the practical mechanics of Tableau's data-source pane.

Core Principles & Definitions

Before diving into Tableau-specific mechanics, it is important to anchor your understanding in a few foundational concepts from relational database theory. Every join operation involves a left table and a right table, connected through one or more join keys — columns whose values are compared row by row to determine which rows should be combined. The choice of join type dictates what happens when a row in one table has no matching counterpart in the other.

1

Inner Join

Returns only the rows where the join key exists in both tables. Non-matching rows from either side are discarded. This is the most restrictive join type and is Tableau's default.
2

Left Join

Keeps all rows from the left table. Where no match exists in the right table, the right-side columns are filled with NULLs. Useful when the left table represents your primary entity.
3

Right Join

The mirror image of a left join — it keeps all rows from the right table and fills left-side columns with NULLs where no match exists. Less commonly used but important for completeness.
4

Full Outer Join

Returns all rows from both tables. Matched rows are combined; unmatched rows from either side appear with NULLs on the opposite side. This is the most inclusive join type.
5

Join Key (Join Clause)

The column (or set of columns) used to match rows across tables. In Tableau, you specify this in the join dialog by selecting a field from each table and an operator (typically equality, =).
KEY TAKEAWAY
Think of joining tables like merging two sorted guest lists for a party. An inner join only lets in guests who appear on both lists. A left join admits everyone on the first list, noting 'unknown' for any details only the second list would have provided. A full outer join admits everyone from both lists regardless, with blanks wherever information is missing. The join key is the guest's name — the shared identifier that links the two lists together.

Visual Explanation — Venn Diagram of Join Types

The classical way to visualize join types is through a Venn diagram, where each circle represents a table and the overlapping region represents rows that match on the join key. The shaded region in each variant shows which rows are included in the result set. Study the diagram below carefully — this mental model will guide every join decision you make in Tableau.

Each quadrant shows one join type. Circle A (blue) represents the left table; circle B (violet) represents the right table. The shaded/filled regions indicate which rows appear in the result. Note how the inner join is the most restrictive (smallest shaded area) and the full outer join is the most inclusive.

In the diagram above, the overlap between circles A and B corresponds to rows where the join key values match. For an inner join, only that overlap is returned. For a left join, the entire left circle is retained, with NULLs filling in for missing right-side data. The right join mirrors this logic for the right circle. Finally, the full outer join is the union of both circles — every row from both tables is preserved, regardless of whether a match exists.

How Joins Work — The Mechanics

Understanding the mechanics of a join requires thinking about it as a set operation governed by a predicate. Given two tables, T_left with m rows and T_right with n rows, the join evaluates a predicate (typically equality on the join key) for every possible pairing of rows. If the predicate evaluates to TRUE, the combined row is included in the output. The join type then determines what to do with rows that never satisfy the predicate.

Formal Definitions

INNER JOIN
T_left ⋈ T_right = { r ∘ s | r ∈ T_left ∧ s ∈ T_right ∧ r.key = s.key }
Where r ∘ s denotes the concatenation of tuples r and s. Only pairs satisfying r.key = s.key are emitted.
LEFT OUTER JOIN
T_left ⟕ T_right = (T_left ⋈ T_right) ∪ { r ∘ NULL | r ∈ T_left ∧ ¬∃ s ∈ T_right : r.key = s.key }
Every row r from the left table is preserved. If no matching s exists, the right-side columns are filled with NULLs.
RIGHT OUTER JOIN
T_left ⟖ T_right = (T_left ⋈ T_right) ∪ { NULL ∘ s | s ∈ T_right ∧ ¬∃ r ∈ T_left : r.key = s.key }
The symmetric counterpart of the left outer join — every row from the right table is preserved, with NULLs on the left side where no match exists.
FULL OUTER JOIN
T_left ⟗ T_right = (T_left ⟕ T_right) ∪ (T_left ⟖ T_right)
The full outer join is the union of the left outer and right outer joins. Every row from both tables appears in the output at least once.
⚠️ Row Count Impact
Be aware that joins can change the row count of your result set. If a key in the left table matches multiple rows in the right table, a one-to-many relationship exists and the left row is duplicated for each match. This phenomenon, called row fanout, can inflate aggregations if not accounted for. Conversely, an inner join can reduce the row count if many rows lack matches. Always verify your row count after joining in Tableau.

Detailed Breakdown — Join Results with Sample Data

The most effective way to internalize the differences among join types is to trace through a concrete example with small tables. Consider two tables: Orders (left) and Customers (right), joined on CustomerID. The Orders table contains four rows (CustomerIDs: 101, 102, 103, 104), and the Customers table contains four rows (CustomerIDs: 101, 102, 105, 106). Notice that IDs 103 and 104 exist only in Orders, while 105 and 106 exist only in Customers. IDs 101 and 102 are shared.

The source tables Orders and Customers share CustomerIDs 101 and 102. The right panel shows how each join type produces a different result set. Pink-colored rows indicate where NULLs are injected due to unmatched keys.

Notice the critical pattern: the inner join yields only 2 rows — the intersection. The left join preserves the 4 Orders rows, padding Name with NULL for customers 103 and 104. The right join preserves the 4 Customers rows, padding Product with NULL for customers 105 and 106. The full outer join produces 6 rows — every row from both tables, with NULLs wherever the other side has no match. In Tableau, these NULLs are visible as blank cells in the data pane and can be handled using IFNULL() or ZN() functions.

Worked Example — Creating a Join in Tableau

Let's walk through a realistic scenario. You have two Excel files: SalesTransactions.xlsx (containing OrderID, ProductID, Quantity, and SaleDate) and ProductCatalog.xlsx (containing ProductID, ProductName, Category, and UnitPrice). You want to build a dashboard that shows total revenue by product category, so you need to combine these two tables on ProductID. Because some products in your catalog may have never been sold, but you still want them listed, you choose a right join (or equivalently, swap the table order and use a left join).

Joining Sales Transactions to Product Catalog in Tableau
1
Step 1 — Connect to the First Data SourceOpen Tableau Desktop, click Microsoft Excel under the Connect pane, and navigate to SalesTransactions.xlsx. Drag the Sheet1 sheet onto the canvas area. This becomes your left table.
The SalesTransactions table appears on the canvas as the left (primary) table.
2
Step 2 — Add the Second TableIn the left panel, click Add next to "Connections" and open ProductCatalog.xlsx. Drag its sheet onto the canvas. Tableau will auto-detect that both tables share a ProductID column and will propose an inner join by default.
Both tables are now on the canvas connected by a join icon (two overlapping circles).
3
Step 3 — Open the Join Dialog and Choose the Join TypeClick the join icon between the two tables. A dialog appears showing four Venn-diagram icons representing inner, left, right, and full outer join. Select the right join icon. Verify that the join clause reads SalesTransactions.ProductID = ProductCatalog.ProductID.
The join is now configured as a right join on ProductID.
4
Step 4 — Validate in the Data PreviewAt the bottom of the Data Source page, review the data grid. Products that have never been sold (e.g., a brand-new item) should appear with NULL values in the OrderID, Quantity, and SaleDate columns. Products that have been sold will show complete data. If you see products missing that you expected, double-check the join key — a common issue is trailing spaces or mismatched data types (e.g., the key is stored as text in one file and numeric in the other).
All products from the catalog appear. Unsold products show NULLs in the sales columns — confirming the right join works correctly.
5
Step 5 — Handle NULLs in the VisualizationNavigate to a new sheet. Drag Category to Rows and create a calculated field Revenue = ZN([Quantity]) × [UnitPrice]. The ZN() function converts NULLs to zero, ensuring that unsold products contribute $0 to their category total rather than producing a NULL aggregation.
A bar chart of Revenue by Category is rendered, with all categories represented including those with zero sales.

Strengths, Limitations & When to Use Each Join

Choosing the right join type is not merely an academic exercise — it directly impacts the correctness and completeness of your analysis. The table below summarizes the trade-offs for each join type, along with common real-world use cases in Tableau.

Comparison of join types with use cases and potential pitfalls
Join TypeRows ReturnedWhen to UseWatch Out For
InnerOnly matched rows from both tablesWhen you only care about entities that exist in both tables (e.g., orders that have a valid customer)Silently drops rows with no match — can cause under-counting if keys are misaligned
LeftAll left rows + matched right rows (NULLs for unmatched right)When the left table is your primary data and you want to enrich it — e.g., adding customer details to a complete transaction logNULLs in right-side columns can propagate into calculations; use ZN() or IFNULL()
RightAll right rows + matched left rows (NULLs for unmatched left)When the right table is your primary entity — functionally identical to swapping tables and using a left joinLess intuitive in Tableau since dragging order defines left/right; consider reordering instead
Full OuterAll rows from both tables (NULLs where no match)Data reconciliation, audit scenarios — finding records that exist in one source but not the otherProduces the largest result set; NULLs appear on both sides; not supported by all data sources
KEY TAKEAWAY
Think of join type selection as a data integrity decision, not just a syntax choice. In the same way that a software engineer selects the correct data structure (array vs. hash map vs. tree) based on access patterns, a data analyst should select a join type based on the analytical question: Do I need completeness on one side? Both sides? Or only the intersection? A wrong join type can silently discard records or introduce phantom NULLs that distort aggregations — bugs that are far harder to detect than a runtime error.

Joins vs. Relationships & Cross-Database Joins

Beginning with Tableau 2020.2, the data model was restructured into two layers: the logical layer (where tables are connected via Relationships) and the physical layer (where traditional joins reside). Relationships are more flexible — Tableau auto-determines the appropriate join type at query time based on which fields are used in the visualization. However, physical-layer joins still offer precise, deterministic control that is essential in many scenarios, such as when you need to force a specific join type, handle complex multi-key joins, or optimize query performance on known one-to-one schemas.

Physical joins vs. logical relationships in Tableau's data model
FeaturePhysical JoinsLogical Relationships
Join type controlExplicitly chosen by the user (inner, left, right, full)Automatically inferred at query time
Row duplicationPossible (fanout in one-to-many joins); user must manage LOD expressions or COUNTDMinimized — Tableau queries each table at its native granularity
NULL handlingNULLs appear immediately in the data source; analyst handles with ZN/IFNULLUnmatched values appear contextually; outer-join semantics applied per visualization
Cross-databaseSupported — e.g., join a SQL Server table with a CSVAlso supported since Tableau 2020.3
Best forDeterministic scenarios, known schemas, complex multi-key joins, data preparationExploratory analysis, multi-fact schemas, avoiding LOD workarounds

Another advanced capability worth noting is cross-database joins. Tableau can join tables from entirely different data sources — for example, a PostgreSQL database joined with a Google Sheets spreadsheet. The mechanics are identical: drag both tables onto the physical layer, select the join type, and map the join keys. Tableau's query federation engine handles the execution, pulling data from each source and performing the join in Tableau's own query pipeline. While powerful, cross-database joins can incur performance overhead because the data must be materialized locally, so they are best reserved for smaller tables or prototyping.

💡 Accessing the Physical Layer
To create a physical join in Tableau 2020.2 or later, you must double-click on a logical table in the canvas to open the physical layer. This is where the traditional join dialog lives. Single-clicking the noodle between two logical tables configures a Relationship, not a join.

Practice Problems

PROBLEM 1CONCEPTUAL
Explain in your own words why an inner join between a table with 1,000 rows and a table with 500 rows might return fewer than 500 rows. Under what circumstances could it return more than 1,000 rows?
PROBLEM 2BASIC CALCULATION
Table A has 6 rows with keys {1, 2, 3, 4, 5, 6}. Table B has 4 rows with keys {2, 4, 7, 8}. How many rows does each join type produce? List the keys present in each result.
PROBLEM 3INTERMEDIATE
You are building a Tableau dashboard that shows all employees alongside their department budgets. The Employees table (5,000 rows) has a DeptID column, and the Departments table (25 rows) has a DeptID and Budget column. Some employees have a NULL DeptID (they are unassigned). Which join type should you use to ensure every employee appears in the dashboard, even those with no department? What will you see in the Budget column for unassigned employees?
PROBLEM 4APPLIED
A data engineering team migrated customer records from a legacy system (LegacyCustomers, 12,000 rows) to a new CRM (NewCRM, 11,500 rows). Both tables share a CustomerID column. Management wants to know: (a) how many customers exist in both systems, (b) how many were lost in migration, and (c) how many exist only in the new system. Which single join type lets you answer all three questions? Write the Tableau calculated fields (using ISNULL) needed to categorize each row.
PROBLEM 5CRITICAL THINKING
Tableau's logical-layer Relationships are marketed as superior to physical-layer joins because they avoid row duplication and let Tableau choose the join type at query time. Despite this, identify and justify at least three scenarios where a data analyst should deliberately bypass Relationships and use physical-layer joins instead.

Lesson Summary

Joins are the fundamental mechanism for combining data from multiple tables in Tableau's physical data layer. The four join types — inner, left, right, and full outer — differ in how they handle unmatched rows. An inner join returns only the intersection, a left join preserves all left-table rows, a right join preserves all right-table rows, and a full outer join preserves everything from both sides. The choice directly impacts your row count, NULL exposure, and the completeness of your analysis.

To create a join in Tableau, drag tables onto the physical-layer canvas, click the join icon, select the desired join type, and verify the join key mapping. Always validate results in the data preview pane, watching for unexpected NULLs (suggesting key mismatches) or row inflation (suggesting one-to-many fanout). Use ZN() and IFNULL() to handle NULLs gracefully. While Tableau's newer Relationships layer automates join-type selection, physical joins remain essential for deterministic control, complex join predicates, and performance-tuned extracts.

Varsity Tutors • Tableau • Joins — Create joins and choose join types (inner/left/right/full)