DB Olympics

Queries · q085 · VP Product · week 1, night 4

Late delivery and returns within apparel merchants, Q4 2025

“Within a single high-return vertical (apparel), do late-delivered orders actually have a higher return rate than on-time ones — controlling for the vertical effect that swamped the merchant-level comparison?”

Manager · asked the questionJonas FeldVP Product. Joined from a mobile-first retailer. Deciding the 2026 roadmap.
Analyst · planned the reportEmeka ObiCustomer-centric: follows cohorts of shoppers or merchants over time.
Engineer · wrote the SQLFelixJunior engineer who nests subqueries in FROM and WHERE (IN, EXISTS, correlated subqueries) rather than 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 VP Product's desk

    Week 1

    We are redesigning the shopper journey for 2026. We need to understand the whole path, from the first visit to checkout, delivery, returns and the next purchase, and where shoppers drop out and why.

  2. Jonas Feld writes to Emeka Obi

    The manager, at the start of week 1

    Subject: Shopper journey end-to-end — what I need for the 2026 roadmap

    Emeka,

    We're resetting the shopper journey for 2026, and I need a clear picture of the whole path — first visit through checkout, delivery, returns, and whether people come back — so we can decide where to invest design and engineering time first. This feeds the roadmap review I'm presenting in two weeks, so the Friday memo should leave me able to say "here's where shoppers are leaking out, and here's the one or two places a fix would move the most volume."

    I know you only get a handful of report slots this week, so please prioritize in the order below — stop earlier in the list if something forces a tradeoff, rather than spreading thin across all of it.

    1. Where do we lose people between landing on the storefront and placing an order? I want to see the shape of the funnel (visit → browse/search → cart → checkout → paid order) and which step is the biggest drop-off, ideally for a few of our bigger merchants so we're not averaging away real differences.
    2. Once someone reaches checkout, what's stopping them from finishing? Is it a one-step cliff or a slow bleed across the checkout flow, and does it differ by device or by how they arrived (e.g. ad vs. direct vs. returning)?
    3. After the order is placed, how is delivery experience affecting trust? I want to understand how often deliveries run late and whether that visibly connects to returns or to people not coming back.
    4. How painful are returns, and does a return kill the relationship? I'd like a sense of how often a return leads to the shopper buying again within a reasonable window versus going quiet.
    5. Who comes back, and how soon? A simple read on repeat purchase behavior — how many first-time buyers return, and roughly how long it takes — would help me know if we're building a roadmap for acquisition or for retention.

    If you can only land three of these this week, do 1, 2 and 5 — funnel, checkout, and repeat purchase are the ones I most need going into the roadmap conversation. Delivery and returns can follow next week if we run out of nights.

    Thanks — looking forward to Friday.

    Jonas

  3. Emeka Obi plans the night

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

    Night 3 lands priority 2 solidly and complicates priority 3 in an interesting way.

    Report 1 (corrected status funnel, retail-only): confirms the clean read — pending→paid loses only 2.4% of orders, essentially instantly (median 0 hours), and paid→fulfilled is 94.9% at a sane ~23-hour median. So payment capture itself is not where retail checkout leaks; it leaks earlier, at cart→order (which Report 1 night 1 already showed at 27-61% conversion for these tenants). Refunds trickle in ~3 weeks out (517h), cancellations are near-instant (0.1h). Priority 2 is now fully answered: it's a slow bleed concentrated in the cart stage, not a cliff at payment.

    Report 2 (cart timing by tenant): the slow-bleed shape is remarkably consistent across all 6 retail tenants — <1hr bucket is ~23-32% of carts and ~100% converted (fast successful checkouts, not failures), while the 1-24hr and 1-7day buckets (roughly two-thirds of all carts, combined) convert at only 1-19%. This is a universal pattern, not one tenant's expiry setting — strong, generalizable finding for the roadmap.

    Report 3 (delivery speed vs. returns) is the interesting twist: at the merchant level, the correlation runs backwards from the "late delivery → more returns" hypothesis. The three apparel merchants (Marrowby & Vane, Studio Vrij, Cragsley Outfitters) have the highest return rates (31-34%) but some of the lowest late-delivery rates (0.3-12%), while food/beauty/pet merchants have high late-delivery rates (20-23%) but near-zero returns (0.5-4.3%). This looks like vertical (apparel fit/size returns are structurally high regardless of delivery speed) is swamping any delivery-speed effect in a merchant-level comparison. Before I tell Jonas "no connection," I want to re-test within a single vertical to remove that confound, and also test the "people not coming back" half of his question directly (repeat purchase after late delivery), which I haven't touched yet.

    This is the last night before the Friday memo. Priorities 1, 2, 5 are in good shape. I'm spending all 3 slots to get a defensible first read on the two things Jonas said could slip to next week if time ran short (delivery trust, and whether a return kills the relationship) — we have the nights, so I'll use them rather than leave those blank in the memo.

    Late delivery and returns within apparel merchants, Q4 2025
    Question
    Within a single high-return vertical (apparel), do late-delivered orders actually have a higher return rate than on-time ones — controlling for the vertical effect that swamped the merchant-level comparison?
    One row per
    tenant and delivery-speed bucket (on-time vs late)
    Columns
    • tenant name
    • delivery bucket (on-time / late)
    • shipments count
    • pct of orders with at least one return
  4. Felix 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
      t.name AS tenant_name,
      base.delivery_bucket,
      count(*) AS shipments_count,
      round(
        100.0 * count(distinct case when exists (
            select 1 from order_returns orr where orr.order_id = base.order_id
          ) then base.order_id end)
        / nullif(count(distinct base.order_id), 0)
      , 1) AS pct_orders_with_return
    FROM (
      select o.tenant_id, o.id as order_id,
        case when (s.delivered_at - s.shipped_at) <= interval '7 days' then 'on-time' else 'late' end as delivery_bucket
      from shipments s
      join fulfillments f on f.id = s.fulfillment_id
      join orders o on o.id = f.order_id
      where s.shipped_at >= timestamp '2025-10-01'
        and s.shipped_at < timestamp '2026-01-01'
        and s.delivered_at is not null
    ) base
    join tenants t on t.id = base.tenant_id
    where t.name in ('Marrowby & Vane', 'Studio Vrij', 'Cragsley Outfitters')
    group by t.name, base.delivery_bucket
    order by t.name, (case when base.delivery_bucket = 'on-time' then 0 else 1 end)

    “Query compiles cleanly with the expected columns. 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 returns one row per tenant × delivery-bucket (on-time/late) for the three named apparel merchants, covering shipments shipped in Q4 2025 with a recorded delivery date, with shipment counts and the % of distinct underlying orders that have at least one return. One note already flagged to the analyst: since a single order can have multiple shipments, an order could in principle land in both buckets for the same tenant if its shipments had different speeds — the return rate is computed per-bucket over whichever distinct orders appear there, matching the requested definition exactly.”

  5. The report comes back overnight

    As Emeka Obi saw it, from the small dataset the agents worked on

    tenant_name         | delivery_bucket | shipments_count | pct_orders_with_return
    --------------------+-----------------+-----------------+-----------------------
    Cragsley Outfitters | on-time         |            1345 |                   37.2
    Cragsley Outfitters | late            |               4 |                    0.0
    Marrowby & Vane     | on-time         |             536 |                   32.8
    Marrowby & Vane     | late            |              73 |                   43.8
    Studio Vrij         | on-time         |             214 |                   36.0
    Studio Vrij         | late            |               3 |                   66.7
    (6 rows)
  6. What came of it

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

    It builds on:

  7. It becomes benchmark query q085

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

    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • made explicita selected t.col gets AS col, its standard name made explicit (2×)
    • 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  t.name AS tenant_name,  base.delivery_bucket,  base.delivery_bucket AS delivery_bucket,  count(*) AS shipments_count,  round(    100.0 * count(distinct case when exists (        select 1 from order_returns orr where orr.order_id = base.order_id      ) then base.order_id end)    / nullif(count(distinct base.order_id), 0)  , 1) AS pct_orders_with_return  100.0 * count(distinct case when exists (      select 1 from order_returns orr where orr.order_id = base.order_id    ) then base.order_id end)  / nullif(count(distinct base.order_id), 0) AS pct_orders_with_returnFROM (  select o.tenant_id, o.id as order_id,  select o.tenant_id AS tenant_id, o.id as order_id,    case when (s.delivered_at - s.shipped_at) <= interval '7 days' then 'on-time' else 'late' end as delivery_bucket  from shipments s  join fulfillments f on f.id = s.fulfillment_id  join orders o on o.id = f.order_id  where s.shipped_at >= timestamp '2025-10-01'    and s.shipped_at < timestamp '2026-01-01'    and s.delivered_at is not null) basejoin tenants t on t.id = base.tenant_idwhere t.name in ('Marrowby & Vane', 'Studio Vrij', 'Cragsley Outfitters')group by t.name, base.delivery_bucketorder by t.name, (case when base.delivery_bucket = 'on-time' then 0 else 1 end)order by t.name NULLS LAST, (case when base.delivery_bucket = 'on-time' then 0 else 1 end) NULLS LAST
    SELECT
      t.name AS tenant_name,
      base.delivery_bucket AS delivery_bucket,
      count(*) AS shipments_count,
      100.0 * count(distinct case when exists (
          select 1 from order_returns orr where orr.order_id = base.order_id
        ) then base.order_id end)
      / nullif(count(distinct base.order_id), 0) AS pct_orders_with_return
    FROM (
      select o.tenant_id AS tenant_id, o.id as order_id,
        case when (s.delivered_at - s.shipped_at) <= interval '7 days' then 'on-time' else 'late' end as delivery_bucket
      from shipments s
      join fulfillments f on f.id = s.fulfillment_id
      join orders o on o.id = f.order_id
      where s.shipped_at >= timestamp '2025-10-01'
        and s.shipped_at < timestamp '2026-01-01'
        and s.delivered_at is not null
    ) base
    join tenants t on t.id = base.tenant_id
    where t.name in ('Marrowby & Vane', 'Studio Vrij', 'Cragsley Outfitters')
    group by t.name, base.delivery_bucket
    order by t.name NULLS LAST, (case when base.delivery_bucket = 'on-time' then 0 else 1 end) NULLS LAST
    100 ms1 sHyper131 msDuckDB184 msGizmoSQL190 msclickhouse_brew805 msFirebolt532 msDataFusionerrorClickHouseerror
    • DataFusionThis feature is not implemented: Physical plan does not support logical expression Exists(Exists { subquery: <subquery>, negated: false })
    • ClickHouseCode: 48. DB::Exception: Correlated subqueries in aggregate function argument are not supported. (NOT_IMPLEMENTED)
  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

    Felix's whole session, 7 turns
    • The request, as Felix received it
      Report request from Emeka Obi (analyst for the VP Product):
      
      Title: Late delivery and returns within apparel merchants, Q4 2025
      Question: Within a single high-return vertical (apparel), do late-delivered orders actually have a higher return rate than on-time ones — controlling for the vertical effect that swamped the merchant-level comparison?
      Grain: one row per tenant and delivery-speed bucket (on-time vs late)
      Columns:
      - tenant name
      - delivery bucket (on-time / late)
      - shipments count
      - pct of orders with at least one return
      Details: Tenants: Marrowby & Vane, Studio Vrij, Cragsley Outfitters (the three apparel merchants that showed high aggregate return rates). Base: shipments joined via fulfillments to orders for tenant_id, where shipments.shipped_at is in 2025-10-01 to 2025-12-31 and delivered_at is not null. delivery_bucket = 'on-time' if (delivered_at - shipped_at) <= 7 days, else 'late' (same 7-day proxy as the earlier delivery-speed report). For each tenant/bucket: shipments_count = count of shipments; pct_orders_with_return = among the distinct orders behind those shipments, the % with at least one order_returns row (order_returns.order_id = orders.id), rounded to 1 decimal. Order rows by tenant_name, then bucket with 'on-time' before 'late'.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Felix calls dry_run
      SELECT
        t.name AS tenant_name,
        base.delivery_bucket,
        count(*) AS shipments_count,
        round(
          100.0 * count(distinct case when exists (
              select 1 from order_returns orr where orr.order_id = base.order_id
            ) then base.order_id end)
          / nullif(count(distinct base.order_id), 0)
        , 1) AS pct_orders_with_return
      FROM (
        select o.tenant_id, o.id as order_id,
          case when (s.delivered_at - s.shipped_at) <= interval '7 days' then 'on-time' else 'late' end as delivery_bucket
        from shipments s
        join fulfillments f on f.id = s.fulfillment_id
        join orders o on o.id = f.order_id
        where s.shipped_at >= timestamp '2025-10-01'
          and s.shipped_at < timestamp '2026-01-01'
          and s.delivered_at is not null
      ) base
      join tenants t on t.id = base.tenant_id
      where t.name in ('Marrowby & Vane', 'Studio Vrij', 'Cragsley Outfitters')
      group by t.name, base.delivery_bucket
      order by t.name, (case when base.delivery_bucket = 'on-time' then 0 else 1 end)
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: tenant_name, delivery_bucket, shipments_count, pct_orders_with_return
    • FelixQuery compiles cleanly with the expected columns. Submitting.
    • Felix calls submit
      SELECT
        t.name AS tenant_name,
        base.delivery_bucket,
        count(*) AS shipments_count,
        round(
          100.0 * count(distinct case when exists (
              select 1 from order_returns orr where orr.order_id = base.order_id
            ) then base.order_id end)
          / nullif(count(distinct base.order_id), 0)
        , 1) AS pct_orders_with_return
      FROM (
        select o.tenant_id, o.id as order_id,
          case when (s.delivered_at - s.shipped_at) <= interval '7 days' then 'on-time' else 'late' end as delivery_bucket
        from shipments s
        join fulfillments f on f.id = s.fulfillment_id
        join orders o on o.id = f.order_id
        where s.shipped_at >= timestamp '2025-10-01'
          and s.shipped_at < timestamp '2026-01-01'
          and s.delivered_at is not null
      ) base
      join tenants t on t.id = base.tenant_id
      where t.name in ('Marrowby & Vane', 'Studio Vrij', 'Cragsley Outfitters')
      group by t.name, base.delivery_bucket
      order by t.name, (case when base.delivery_bucket = 'on-time' then 0 else 1 end)
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • FelixSubmitted. The report returns one row per tenant × delivery-bucket (on-time/late) for the three named apparel merchants, covering shipments shipped in Q4 2025 with a recorded delivery date, with shipment counts and the % of distinct underlying orders that have at least one return. One note already flagged to the analyst: since a single order can have multiple shipments, an order could in principle land in both buckets for the same tenant if its shipments had different speeds — the return rate is computed per-bucket over whichever distinct orders appear there, matching the requested definition exactly.