CodeRigor

FREE LESSON

Join contracts and fanout checks

Enforce a many-to-one relationship before enriching rows; preserve left-row grain and expose unmatched keys.

Before combining tables, state their grain: what does one row represent? In this build, one left row is an order and one right row is a customer. The intended relationship is many orders to one customer. Enriching an order with a customer name should leave the number of orders and the sum of their amounts unchanged. This is a correctness condition, not just a performance preference.

A repeated right key can multiply evidence in a general join. Two orders for customer A and three customer rows for A produce six joined pairs. Summing order amounts afterward counts each order three times. Selecting an arbitrary right row avoids that multiplication but silently chooses evidence. Validate or resolve the relationship before reporting the result.

A validated index protects left-row grain
start / 2
Each left row makes one lookup and produces exactly one output row.
A validated index protects left-row grain
Each left row makes one lookup and produces exactly one output row.

Prove uniqueness before lookup

Python
orders = [{'customer_id': 'A', 'cents': 100}, {'customer_id': 'A', 'cents': 200}]
customers = [{'id': 'A', 'name': 'Ada'}, {'id': 'A', 'name': 'Ada'}]
pairs = [(order, customer) for order in orders for customer in customers
         if order['customer_id'] == customer['id']]
print(len(pairs), sum(order['cents'] for order, customer in pairs))

There are four pairs and 600 cents, even though the two orders total 300 cents. Equal right payloads still violate the unique-key contract. In the build, inspect the complete right input and raise on every repeated id before enriching orders. That includes an unused duplicate key. Upstream deduplication can supply a clean unique right table with its own ledger; the join must not silently do that work.

Keys arrive already normalized here. The join rejects missing, blank, non-string or boundary-padded ids. Keeping normalization outside the join makes its key comparison explicit and reusable. Case stays significant. Joining "A" to "a" without an agreed normalization rule can connect different entities.

Left preservation differs from inner filtering
start / 2
An unknown customer remains a visible order with a None name.
Left preservation differs from inner filtering
An unknown customer remains a visible order with a None name.

Match absence explicitly

A left join emits one fresh shallow dictionary for every order. Add the matched name, or None when no customer exists. The unmatched ledger records original 1-based order positions. An empty string name is still a match under this join contract; testing the name's truthiness would confuse a payload value with key absence. Compare the lookup result with None instead.

The output field itself is another boundary. If an order already contains customer_name, overwriting it could hide prior enrichment or a source schema change. The build rejects that collision, even when its value is None. Other left payload fields are preserved, and the function's own enrichment does not mutate source dictionaries. Nested payloads remain shallowly shared.

After joining, verify the left count and unmatched count, then check totals at the intended grain. Matching counts do not prove the keys or sources are true, but failing counts disprove the stated relationship. Try identical right customers, two left orders for one customer, an unused duplicate, an unknown customer and an existing output field before implementing the function.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Review 46:37–57:13 for choosing a record key, and 1:07:49–1:14:05 for named fields. The authored diagrams and build teach join cardinality; the video supplies Python record-processing preparation.