DB Olympics

Queries · q372 · Head of Lifecycle Marketing · week 2, night 1

Loyalty transaction order-linkage diagnostic by direction

“Before retesting the rewards-redemption-without-purchase hypothesis, is order_id even populated on redemption-direction loyalty_transactions, or do we need a different way to connect a redemption to an order?”

Manager · asked the questionAisha RahmanHead of Lifecycle Marketing. Ran customer messaging at a subscription box company.
Analyst · planned the reportIngrid SolbergRisk-focused: looks for the tail, the outliers and the worst cases.
Engineer · wrote the SQLViktorOld-school warehouse engineer: explicit JOIN chains straight to the base tables, derived tables, GROUP BY with CASE pivots, few CTEs.

Fictional people at a fictional company, each played by a language-model agent. Who they are and what they are told

  1. A business event lands on the Head of Lifecycle Marketing's desk

    Week 1; shared with Tobias Lindqvist, Chief Financial Officer

    Is the loyalty and referral programme worth it? Do members and referred customers behave differently from others, and what does the programme cost?

  2. Aisha Rahman writes to Ingrid Solberg

    The manager, at the start of week 2

    Subject: Re: Loyalty & referral — thank you, and where to dig next

    Ingrid, this is excellent — especially catching that the refund-rate gap was a vertical mix artifact. Good instinct to go back and break that out rather than let the scary headline stand.

    What surprised me most, and what I want explained before we take this to Tobias as a joint recommendation: a 19.4% cost-to-member-revenue ratio is strikingly high, and members showing lower revenue and order counts than non-members is the opposite of what a loyalty programme is supposed to produce. I don't want to present "the programme loses money" to leadership until I understand whether that's a true causal effect or another mix artifact like the refund rate turned out to be — since 72% of members sit in one vertical, I'm wary of a second apples-to-oranges comparison hiding in there.

    Questions for this week, in my own words:

    1. Within Apparel alone — since that's where almost all members live — do members still look worse off than similar non-member customers in that same vertical, once we also account for how long they've been customers? That's the comparison I actually trust as a verdict on the programme.
    2. Is the growing points liability a timing issue or a real design flaw? I want to understand whether we're simply in a "young programme, redemptions lag issuance" phase that will level out, or whether the redemption rate structurally understates true future cost — i.e., should I expect that €491k to keep climbing indefinitely at this pace.
    3. Can we fix the redemption-to-order linkage well enough to test the gaming hypothesis properly? That was left untested, not cleared, and it's exactly the kind of finding that would change my recommendation, so I'd like one more serious attempt before we call it inconclusive for good.
    4. If the member economics do hold up as genuinely negative, is there a design change that would plausibly fix it — rather than only "keep, cut, or extend to B2B" as the choice — are there any patterns in how the better-performing members (if any exist) use the programme differently from the rest? I don't need a redesign from you, just whether the data shows any sign of what a healthier version would look like.

    The B2B extension question can wait — I agree we shouldn't open that door until we trust the member economics number. Let's keep that out of this week's slots unless there's room left over.

    Thanks again, Ingrid — this is exactly the kind of rigor I want from this team.

    Best, Aisha

  3. Ingrid Solberg plans the night

    The analyst · week 2, night 1, request 3 of 3

    Aisha's push is right: with 72% of members in one vertical, the revenue/order gap could be a second Simpson's-paradox case just like refunds were. Tonight I'm prioritizing her questions 1-3 in order since she explicitly ranked the apparel-only comparison as the one she'll trust as a verdict, and flagged the liability trajectory and the redemption-linkage retest as the two things that could change the recommendation. Before rebuilding the gaming-hypothesis join (which returned zero matches last time), I'm first running a cheap diagnostic on whether order_id is ever populated on redemption-direction loyalty_transactions at all - if it's structurally never set, I need a different join strategy (e.g. time-proximity matching) rather than repeating the same failed approach, and I'd rather spend a slot finding that out now than waste a bigger request later. Holding question 4 (what better-performing members look like) and the B2B question for later nights, per Aisha's explicit deprioritization.

    Loyalty transaction order-linkage diagnostic by direction
    Question
    Before retesting the rewards-redemption-without-purchase hypothesis, is order_id even populated on redemption-direction loyalty_transactions, or do we need a different way to connect a redemption to an order?
    One row per
    distinct loyalty_transactions.direction value
    Columns
    • direction
    • transaction_count
    • transactions_with_order_id
    • pct_with_order_id
    • distinct_order_ids_referenced
  4. Viktor writes the SQL

    The engineer · 1 dry run on the empty schema, then the submission

    Dry run 1 · STATUS: COMPILES (dry run on the empty schema, no data read)
    select
      direction,
      count(*) as transaction_count,
      count(order_id) as transactions_with_order_id,
      round(100.0 * count(order_id) / nullif(count(*), 0), 2) as pct_with_order_id,
      count(distinct order_id) as distinct_order_ids_referenced
    from loyalty_transactions
    where occurred_at >= date '2023-01-01'
      and occurred_at < date '2026-01-01'
    group by direction
    order by transaction_count desc, direction

    “Looks good — submitting.”

    Submitted · the SQL of the last dry run, unchanged · Submitted to tonight's batch. Your work on this request is done.

    “Submitted. The report will show, per direction value (e.g. earn/redeem), how many loyalty_transactions rows exist, how many have a non-null order_id, the percentage with an order_id, and how many distinct orders are referenced — which directly answers whether order_id linkage is usable for the redemption-to-order hypothesis or whether a time-proximity matching approach is needed instead.”

  5. The report comes back overnight

    As Ingrid Solberg saw it, from the small dataset the agents worked on

    direction | transaction_count | transactions_with_order_id | pct_with_order_id | distinct_order_ids_referenced
    ----------+-------------------+----------------------------+-------------------+------------------------------
    earn      |              3931 |                       3931 |             100.0 |                          3931
    burn      |               343 |                          0 |               0.0 |                             0
    (2 rows)
  6. What came of it

    The memo and the queries that followed; links found by title, so inferred

    Later queries that build on this report:

    It builds on:

  7. It becomes benchmark query q372

    Changed only where the benchmark needs the same result on every system

    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • determinismthe standard leaves the place of NULLs in a sort to the implementation: NULLS LAST ascending, NULLS FIRST descending, as in the reference results (2×)
    The benchmark text, against the submitted SQL
    select  direction,  count(*) as transaction_count,  count(order_id) as transactions_with_order_id,  round(100.0 * count(order_id) / nullif(count(*), 0), 2) as pct_with_order_id,  100.0 * count(order_id) / nullif(count(*), 0) as pct_with_order_id,  count(distinct order_id) as distinct_order_ids_referencedfrom loyalty_transactionswhere occurred_at >= date '2023-01-01'  and occurred_at < date '2026-01-01'group by directionorder by transaction_count desc, directionorder by transaction_count desc NULLS FIRST, direction NULLS LAST
    select
      direction,
      count(*) as transaction_count,
      count(order_id) as transactions_with_order_id,
      100.0 * count(order_id) / nullif(count(*), 0) as pct_with_order_id,
      count(distinct order_id) as distinct_order_ids_referenced
    from loyalty_transactions
    where occurred_at >= date '2023-01-01'
      and occurred_at < date '2026-01-01'
    group by direction
    order by transaction_count desc NULLS FIRST, direction NULLS LAST
    10 ms100 ms1 sHyper19.6 msDuckDB27.6 msGizmoSQL28.5 msclickhouse_brew75.8 msFirebolt33.2 msDataFusion195 msClickHouse201 ms
  8. Everything, as recorded

    The agents' own records, as the role play wrote them; only the personal data of the person who ran it is redacted

    Viktor's whole session, 7 turns
    • The request, as Viktor received it
      Report request from Ingrid Solberg (analyst for the Head of Lifecycle Marketing):
      
      Title: Loyalty transaction order-linkage diagnostic by direction
      Question: Before retesting the rewards-redemption-without-purchase hypothesis, is order_id even populated on redemption-direction loyalty_transactions, or do we need a different way to connect a redemption to an order?
      Grain: one row per distinct loyalty_transactions.direction value
      Columns:
      - direction
      - transaction_count
      - transactions_with_order_id
      - pct_with_order_id
      - distinct_order_ids_referenced
      Details: Source: loyalty_transactions across all tenants, 2023-01-01 to 2025-12-31. Group by direction. transaction_count = total rows for that direction. transactions_with_order_id = count where order_id is not null. pct_with_order_id = transactions_with_order_id divided by transaction_count as a percentage. distinct_order_ids_referenced = count of distinct non-null order_id values for that direction. This is a diagnostic to determine whether order_id linkage is usable at all for testing the redemption-to-refund hypothesis, or whether an alternative approach (e.g. matching by time proximity between a transaction and the customer's orders) will be needed instead. Order by transaction_count descending.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Viktor calls dry_run
      select
        direction,
        count(*) as transaction_count,
        count(order_id) as transactions_with_order_id,
        round(100.0 * count(order_id) / nullif(count(*), 0), 2) as pct_with_order_id,
        count(distinct order_id) as distinct_order_ids_referenced
      from loyalty_transactions
      where occurred_at >= date '2023-01-01'
        and occurred_at < date '2026-01-01'
      group by direction
      order by transaction_count desc, direction
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: direction, transaction_count, transactions_with_order_id, pct_with_order_id, distinct_order_ids_referenced
    • ViktorLooks good — submitting.
    • Viktor calls submit
      select
        direction,
        count(*) as transaction_count,
        count(order_id) as transactions_with_order_id,
        round(100.0 * count(order_id) / nullif(count(*), 0), 2) as pct_with_order_id,
        count(distinct order_id) as distinct_order_ids_referenced
      from loyalty_transactions
      where occurred_at >= date '2023-01-01'
        and occurred_at < date '2026-01-01'
      group by direction
      order by transaction_count desc, direction
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • ViktorSubmitted. The report will show, per `direction` value (e.g. earn/redeem), how many loyalty_transactions rows exist, how many have a non-null `order_id`, the percentage with an order_id, and how many distinct orders are referenced — which directly answers whether `order_id` linkage is usable for the redemption-to-order hypothesis or whether a time-proximity matching approach is needed instead.