Joins II — fan-out & grain
Concept  ·  SQL & Querying

A bridge table multiplies both sides — the grain explodes in two directions at once.

The bridge is honest — many-to-many is the business fact — the trap is grain amnesia on the far side of the walk. After karts→bookings, the grain is the relationship (kart × group), so kart-grain columns like fee appear once per booking. No data is dirty and no join is wrong; the multiplication is structural, so only computing each metric at its own grain fixes it.

See it break
karts
kartfee
k110
k210
bookings
kartgrp
k1g1
k1g2
k2g3
The trap
SELECT
  SUM(k.fee) AS value
FROM
  karts k
  JOIN bookings b ON b.kart = k.kart
  ;
The fix
SELECT
  SUM(k.fee) AS value
FROM
  karts k
WHERE
  EXISTS (
    SELECT
      1
    FROM
      bookings b
    WHERE
      b.kart = k.kart
  );
The trap
30
The fix
20

The fleet value read 30 for karts worth 20 — joining through the bookings bridge made the grain kart×group, so each kart's fee counted once per booking.

The rule

Pre-aggregate the bridge to the entity's grain; EXISTS for has-any-booking questions; a grain sentence before any SUM through a bridge.

Shows up elsewhere
Fan-out before aggregateDetecting fan-out
Try one →Prove it in practice →