

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Difficulty: 3
click for more info
Not enough gems
Cost: 6 gems
1: Data Merging
incomplete
2: Inner and Left Joins
incomplete
3: Outer Joins
incomplete
4: Merging on Different Keys
incomplete
5: Merging on Composite Keys
incomplete
6: Handling Column Name Conflicts
incomplete
7: Understanding Cardinality
incomplete
8: Merge Validation
incomplete
9: Finding Unmatched Records
incomplete
10: Multi-Table Joins
incomplete
11: Concatenating DataFrames
incomplete
12: Standardizing Schemas
incomplete
13: Building an Integration Pipeline
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
Outer joins are less common than inner and left, but they can be useful to solve specific problems. As for "right" joins... they're dumb. A right join is just a left join with the DataFrames swapped. Don't use them.
An "outer" join keeps all rows from both DataFrames, filling in NaN where data is missing from either side.
sales = pd.DataFrame(
{"product_id": ["CHL-482", "TST-731", "OVN-205"], "quantity": [10, 20, 30]}
)
products = pd.DataFrame(
{
"product_id": ["CHL-482", "TST-731", "BRW-619"],
"name": ["ChillVault Mini", "ToastForge Pro", "BrewPilot"],
}
)
result = pd.merge(sales, products, on="product_id", how="outer")
print(result)
# product_id quantity name
# 0 BRW-619 NaN BrewPilot
# 1 CHL-482 10.0 ChillVault Mini
# 2 OVN-205 30.0 NaN
# 3 TST-731 20.0 ToastForge Pro
With this join, everything survives the merge. Product OVN-205 has a name of NaN, and product BRW-619 has a quantity of NaN.
Use outer joins when: you want to see everything, including gaps. This is especially useful for audits and data quality checks.
Count rows to understand your data overlap:
inner_count = len(pd.merge(sales, products, on="product_id", how="inner"))
left_count = len(pd.merge(sales, products, on="product_id", how="left"))
outer_count = len(pd.merge(sales, products, on="product_id", how="outer"))
print(f"Inner: {inner_count}") # 2 (only matches)
print(f"Left: {left_count}") # 3 (all sales)
print(f"Outer: {outer_count}") # 4 (everything)
In a larger dataset, if inner_count were much smaller than left_count, you'd probably have a lot of sales with invalid product IDs. That's a data-quality problem worth investigating.
SnackStack's analytics team wants a quick overlap report for product sales: how many rows survive each type of join?
Complete the count_join_rows function. It accepts two DataFrames: sales and products.