The four types
Joins combine tables from the same data source into one flat table, row by row, on a matching key.
Inner keeps only rows that match on both sides. Left keeps every row from the left table and fills nulls where the right has no match. Right does the reverse. Full outer keeps everything from both, with nulls wherever there's no counterpart.
Left joins are the safe default when the left table is your fact table and you're enriching it with lookups — you never silently lose fact rows.
The duplication trap
This catches almost everyone once. If one order has three line items and you join Orders to Line Items, the order-level fields repeat three times. SUM(Order Total) is now triple-counted.
The fix depends on the question. Aggregate before joining, use SUM({FIXED [Order ID] : MIN([Order Total])}) to de-duplicate, or restructure so you're not mixing granularities in one view. The important thing is to notice — check row counts before and after a join.
Assume Referential Integrity
Under the Data menu, this tells Tableau that every row in one table has a guaranteed match in the other. When it's on, Tableau can omit joined tables from a query entirely if no field from them appears in the view, which can speed things up considerably.
Only enable it if your data genuinely enforces that relationship. If it doesn't, you'll get wrong numbers rather than an error — which is far worse than a slow query.
Join calculations and cross-database joins
When keys don't match cleanly you can create a join calculation — join on UPPER([Name]) or on a concatenation of two fields.
Tableau also supports cross-database joins, combining tables from different connections (say SQL Server and a CSV) into a single joined data source. That's distinct from blending, which we cover separately.