Prerequisites
- A Narrative I/O account with access to multiple datasets
- Understanding of filtering and transforming data
What you’ll learn
- How to use INNER JOIN to match records across datasets
- How to use LEFT JOIN for optional matches
- How to chain multiple JOINs
- How to use anti-joins to find unmatched records
- How to join with Rosetta Stone for identity resolution
- Performance considerations for large joins
INNER JOIN
An INNER JOIN returns only rows that have matching values in both datasets.Basic syntax
Example: Enriching customer data
Combine customer information with their orders:Only customers who have orders (and orders with valid customers) appear in the results. Customers without orders are excluded.
Using table aliases
Aliases make queries more readable and are required when referencing columns:LEFT JOIN
A LEFT JOIN returns all rows from the left table, plus matching rows from the right table. Unmatched rows have NULL values for right-table columns.Basic syntax
Example: Find customers with or without orders
order_count = 0.
Filtering LEFT JOIN results
To find records without matches, filter for NULL:Multiple JOINs
Chain JOINs to combine data from three or more datasets:Mixing JOIN types
You can mix INNER and LEFT JOINs:Anti-joins with NOT EXISTS
Find records in one dataset that don’t have matches in another:Basic anti-join
Example: Find inactive users
Find users who haven’t logged in recently:Joining with Rosetta Stone
Rosetta Stone enables identity resolution across datasets using normalized identifiers.Access Rosetta Stone identifiers
Join datasets via Rosetta Stone
Match records across datasets using resolved identities:Query Rosetta Stone directly
Rosetta Stone queries can be scoped to different levels: global (
narrative.rosetta_stone), company-specific (company_data._rosetta_stone), or dataset-specific (company_data."123"._rosetta_stone). See Rosetta Stone table references for complete syntax.Join conditions
Multiple conditions
Join on multiple columns:Complex conditions
Use expressions in join conditions:NULL-safe joins
UseIS NOT DISTINCT FROM for NULL-safe equality:
Self-joins
Join a dataset to itself for comparisons:Subqueries in JOINs
Join with aggregated or transformed data:Performance considerations
Use fully qualified column names
Always qualify column names in joins to avoid ambiguity and improve query parsing:Filter before joining
Apply filters as early as possible to reduce the data being joined:Avoid OR in join conditions
OR conditions in joins can cause performance issues:Include budget controls
Always include budget controls when joining datasets in materialized views:Common patterns
Enrich with latest record
Get the most recent related record for each row:Aggregate before joining
Pre-aggregate to reduce join complexity:Related content
Join Performance
Understanding performance implications
Query Optimization
Tips for faster queries
Complex Joins Cookbook
Advanced join patterns and examples
Rosetta Stone
Identity resolution for cross-dataset matching

