SQL joins, in Pandas dialect
pd.merge(left, right, on='key', how='inner|left|right|outer') implements the same four join types you know from SQL, plus one extra (cross). It's the workhorse for combining tables, and it's also where the highest-impact silent bugs live, because Pandas does not warn you when a join changes the row count in a way that's almost certainly wrong.
The four classic gotchas
- Implicit one-to-many fan-out. If the right table has duplicates on the key, an inner/left join fans out left rows. A 1,000-row left table can become 8,500 rows after the join — and you might not notice until your revenue triples.
- Type mismatch on the key. Joining a string
'42'against an integer42matches nothing.customer_idasint64on one side andstring[pyarrow]on the other is a real-world classic. - Whitespace and case mismatches.
'NewYork'and'New York'don't join.'NEW YORK'and'New York'don't join. Strip and normalize before merging. - Many-to-many that becomes silent Cartesian. The same key on both sides duplicated multiple times multiplies rows. Validate cardinality before you merge.
Pandas exposes a validate= argument on merge precisely for the cardinality gotchas. Always use it. validate='one_to_one', 'one_to_many', or 'many_to_one' raises an explicit error if the relationship doesn't hold — which is what you want.