The fields an offer needs, and five pulls that build every table in this book.
Every pull below runs on an orders table, an order-lines table and a customers table. Resolve identity first: customer ID, then normalized email, then phone. A customer who checked out as a guest and later made an account is one customer, and counting them twice turns a repeat buyer into two one-timers.
| Field | On | Written when | Rule |
|---|---|---|---|
first_order_at | Customer | First paid order | Set once, never overwritten |
first_offer | Customer | First paid order | The offer that won them: code, landing page or campaign, mapped to your offer list |
first_products | Customer | First paid order | Product IDs in the first order |
first_discount_pct | Customer | First paid order | Discount as a share of the full-price subtotal |
holdout_digit | Customer or visitor | Profile creation | Random 0 to 9, set once, never recomputed |
existing_customer_at_order | Order | Every order | True if the customer had a prior paid order; used to count cannibalized codes |
-- first products and what their buyers did next
WITH firsts AS (
SELECT customer_id, MIN(ordered_at) AS first_at
FROM orders WHERE status = 'paid'
GROUP BY customer_id
HAVING MIN(ordered_at) <= CURRENT_DATE - 180
),
first_lines AS (
SELECT f.customer_id, l.product_id
FROM firsts f
JOIN orders o ON o.customer_id = f.customer_id AND o.ordered_at = f.first_at
JOIN order_lines l ON l.order_id = o.order_id
),
after AS (
SELECT f.customer_id,
COUNT(o.order_id) FILTER (WHERE o.ordered_at > f.first_at
AND o.ordered_at <= f.first_at + 180) AS reorders,
SUM(o.net_revenue) FILTER (WHERE o.ordered_at <= f.first_at + 180) AS rev_180
FROM firsts f JOIN orders o ON o.customer_id = f.customer_id
WHERE o.status = 'paid'
GROUP BY f.customer_id
)
SELECT fl.product_id,
COUNT(DISTINCT fl.customer_id) AS first_orders,
AVG((a.reorders > 0)::int) AS reorder_rate_180,
AVG(a.rev_180) AS revenue_180
FROM first_lines fl JOIN after a USING (customer_id)
GROUP BY fl.product_id
ORDER BY first_orders DESC;
A customer whose first order contains two products counts toward both. That’s intended: you want to know what each door leads to. For a clean split, rerun it on single-product first orders only and compare.
This is one chapter of The First Offer, which is free and readable in full on a single page with no form in front of it.