DB Olympics

Queries · q079 · VP Product · week 1, night 2

Session-tracking coverage vs order volume for top merchants, 2025

“Does the >100% visit-to-cart ratio in the Q4 funnel reflect real shopper behavior, or is web-session tracking sparse relative to order volume for certain merchants (e.g. subscription sellers), making 'visits' an unreliable denominator for them?”

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 2, request 1 of 3

    Reading the three reports critically:

    Report 1 (funnel): several tenants show visit→cart conversion ABOVE 100% (up to 191.5%), which is impossible for a real per-visitor funnel. The engineer's note explains why: stages are counted independently with no row-level join, so this isn't "% of visitors who added to cart" — it's just cart_count/visit_count. The merchants with the worst over-100% ratios (Brennquell Kaffee, Spice Route Box, Grind Collective, Honeycomb Larder) read like subscription/recurring-box businesses, while the merchants with ratios close to 100-150% and a big cart→order drop (Kibblewick, Studio Vrij, Petalcourt Beauty, Marrowby & Vane, Cragsley Outfitters, Ampfeld Elektronik) read like regular one-off retail. My hypothesis: subscription merchants generate many carts/orders from recurring billing that never involve a fresh tracked web session, which would make "visits" structurally incomparable across merchant types. I want to test that before telling Jonas where the "biggest leak" is, otherwise I'd be mixing a tracking-coverage artifact with real shopper drop-off.

    For the real retail merchants, the consistent, trustworthy signal across stages is: cart→order is the dominant drop (27-61% conversion) while order→paid is consistently high (94-99%). That's the leak worth roadmapping — but I want one more clean (schema-safe) cut at where in that drop it happens, since Report 2's device/channel attempt failed.

    Report 2 (checkout by device/channel): 16,987 of ~17,158 carts (99%) landed in device=unknown/channel=unknown — the engineer flagged exactly this risk. This means the user_id-based same-day join to web_sessions essentially didn't work (most carts are likely guest/anonymous, with no user_id to match on). I'm treating device/channel-by-cart as not reliably answerable with the current schema and pivoting to schema-clean alternatives (order_status_history for stall location; cart timestamps for cliff-vs-bleed shape) rather than re-trying the same fragile join.

    Report 3 (repeat purchase): looks internally consistent — no red flags. Repeat-within-90-days sits in a 40-62% band, median days-to-second-order 32-78 days, with the two most recent cohorts showing lower medians as expected from a shorter observation window. I consider priority 5 answered; no follow-up planned tonight.

    Tonight's 3 requests: (A) test the subscription-vs-session-tracking-gap hypothesis from Report 1, (B) find exactly which status the post-checkout order stalls at using the clean orders/order_status_history join (no fragile session join needed), (C) check whether cart abandonment is a quick cliff or a slow lingering bleed using carts' own timestamps, restricted to the real-retail tenants so we're not mixing in the subscription pattern.

    Session-tracking coverage vs order volume for top merchants, 2025
    Question
    Does the >100% visit-to-cart ratio in the Q4 funnel reflect real shopper behavior, or is web-session tracking sparse relative to order volume for certain merchants (e.g. subscription sellers), making 'visits' an unreliable denominator for them?
    One row per
    tenant, for the same 10 tenants as the Q4 2025 funnel report
    Columns
    • tenant name
    • industry
    • visits in 2025 (web_sessions count)
    • orders placed in 2025
    • visits per order
    • subscription-linked orders % (orders with a matching invoice whose subscription_id is not null)
    • active subscriptions (current count, status = active)
  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,
      t.industry,
      COALESCE(v.visits_2025, 0) AS visits_2025,
      COALESCE(o.orders_2025, 0) AS orders_2025,
      ROUND(COALESCE(v.visits_2025, 0)::numeric / NULLIF(COALESCE(o.orders_2025, 0), 0), 2) AS visits_per_order,
      ROUND(100.0 * COALESCE(s.sub_linked_orders, 0) / NULLIF(COALESCE(o.orders_2025, 0), 0), 1) AS subscription_linked_orders_pct,
      COALESCE(a.active_subscriptions, 0) AS active_subscriptions
    FROM tenants t
    LEFT JOIN (
      SELECT tenant_id, COUNT(*) AS visits_2025
      FROM web_sessions
      WHERE started_at >= DATE '2025-01-01' AND started_at < DATE '2026-01-01'
      GROUP BY tenant_id
    ) v ON v.tenant_id = t.id
    LEFT JOIN (
      SELECT tenant_id, COUNT(*) AS orders_2025
      FROM orders
      WHERE placed_at >= DATE '2025-01-01' AND placed_at < DATE '2026-01-01'
      GROUP BY tenant_id
    ) o ON o.tenant_id = t.id
    LEFT JOIN (
      SELECT o2.tenant_id, COUNT(*) AS sub_linked_orders
      FROM orders o2
      WHERE o2.placed_at >= DATE '2025-01-01' AND o2.placed_at < DATE '2026-01-01'
        AND EXISTS (
          SELECT 1 FROM invoices i
          WHERE i.order_id = o2.id AND i.subscription_id IS NOT NULL
        )
      GROUP BY o2.tenant_id
    ) s ON s.tenant_id = t.id
    LEFT JOIN (
      SELECT tenant_id, COUNT(*) AS active_subscriptions
      FROM subscriptions
      WHERE status = 'active'
      GROUP BY tenant_id
    ) a ON a.tenant_id = t.id
    WHERE t.name IN (
      'Brennquell Kaffee', 'Spice Route Box', 'Grind Collective', 'Honeycomb Larder',
      'Kibblewick', 'Studio Vrij', 'Petalcourt Beauty', 'Marrowby & Vane',
      'Cragsley Outfitters', 'Ampfeld Elektronik'
    )
    ORDER BY visits_per_order ASC, tenant_name ASC

    “Query compiles and returns 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 gives one row per tenant (the same 10 from the Q4 funnel) with visits, orders, visits-per-order, subscription-linked order share, and current active subscriptions — ordered most session-sparse first, which should directly show whether the inflated visit-to-cart ratio concentrates in subscription-heavy merchants with thin session tracking.”

  5. The report comes back overnight

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

    tenant_name         | industry             | visits_2025 | orders_2025 | visits_per_order | subscription_linked_orders_pct | active_subscriptions
    --------------------+----------------------+-------------+-------------+------------------+--------------------------------+---------------------
    Brennquell Kaffee   | Food & Coffee        |        2206 |        4195 |             0.53 |                            0.0 |                  197
    Spice Route Box     | Food & Coffee        |         465 |         780 |              0.6 |                            0.0 |                   33
    Grind Collective    | Food & Coffee        |         697 |        1111 |             0.63 |                            0.0 |                   54
    Honeycomb Larder    | Food & Coffee        |         455 |         620 |             0.73 |                            0.0 |                   32
    Kibblewick          | Pet Supplies         |         667 |         672 |             0.99 |                            0.0 |                   40
    Petalcourt Beauty   | Beauty               |        1221 |         706 |             1.73 |                            0.0 |                    0
    Marrowby & Vane     | Apparel & Footwear   |        3699 |        1758 |              2.1 |                            0.0 |                    0
    Studio Vrij         | Apparel & Footwear   |        1404 |         631 |             2.23 |                            0.0 |                    0
    Cragsley Outfitters | Apparel & Footwear   |        8134 |        3635 |             2.24 |                            0.0 |                    0
    Ampfeld Elektronik  | Consumer Electronics |        1483 |         449 |              3.3 |                            0.0 |                    0
    (10 rows)
  6. What came of it

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

    Emeka Obi's memo to Jonas Feld at the end of the week:

    • 1. Storefront → order funnel

      The biggest leak for our one-off retail merchants (apparel, beauty, electronics, pet) is cart → order, converting at only 27–61% (vs. 94–99% order → paid). Report: "Storefront-to-order funnel, Q4 2025"; "Session-tracking coverage vs order volume."

    Later queries that build on this report:

    It builds on:

  7. It becomes benchmark query q079

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

    • spellingcast
    • determinismtie-breaker: tenant names are not unique
    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision; bare NUMERIC cast that only served the rounding removed; intended fraction: integer numerator cast to NUMERIC(18,6) before the division
    • 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 (3×)
    The benchmark text, against the submitted SQL
    SELECT  t.name AS tenant_name,  t.industry,  t.industry AS industry,  COALESCE(v.visits_2025, 0) AS visits_2025,  COALESCE(o.orders_2025, 0) AS orders_2025,  ROUND(COALESCE(v.visits_2025, 0)::numeric / NULLIF(COALESCE(o.orders_2025, 0), 0), 2) AS visits_per_order,  ROUND(100.0 * COALESCE(s.sub_linked_orders, 0) / NULLIF(COALESCE(o.orders_2025, 0), 0), 1) AS subscription_linked_orders_pct,  CAST(COALESCE(v.visits_2025, 0) AS numeric(18,6)) / NULLIF(COALESCE(o.orders_2025, 0), 0) AS visits_per_order,  100.0 * COALESCE(s.sub_linked_orders, 0) / NULLIF(COALESCE(o.orders_2025, 0), 0) AS subscription_linked_orders_pct,  COALESCE(a.active_subscriptions, 0) AS active_subscriptionsFROM tenants tLEFT JOIN (  SELECT tenant_id, COUNT(*) AS visits_2025  FROM web_sessions  WHERE started_at >= DATE '2025-01-01' AND started_at < DATE '2026-01-01'  GROUP BY tenant_id) v ON v.tenant_id = t.idLEFT JOIN (  SELECT tenant_id, COUNT(*) AS orders_2025  FROM orders  WHERE placed_at >= DATE '2025-01-01' AND placed_at < DATE '2026-01-01'  GROUP BY tenant_id) o ON o.tenant_id = t.idLEFT JOIN (  SELECT o2.tenant_id, COUNT(*) AS sub_linked_orders  SELECT o2.tenant_id AS tenant_id, COUNT(*) AS sub_linked_orders  FROM orders o2  WHERE o2.placed_at >= DATE '2025-01-01' AND o2.placed_at < DATE '2026-01-01'    AND EXISTS (      SELECT 1 FROM invoices i      WHERE i.order_id = o2.id AND i.subscription_id IS NOT NULL    )  GROUP BY o2.tenant_id) s ON s.tenant_id = t.idLEFT JOIN (  SELECT tenant_id, COUNT(*) AS active_subscriptions  FROM subscriptions  WHERE status = 'active'  GROUP BY tenant_id) a ON a.tenant_id = t.idWHERE t.name IN (  'Brennquell Kaffee', 'Spice Route Box', 'Grind Collective', 'Honeycomb Larder',  'Kibblewick', 'Studio Vrij', 'Petalcourt Beauty', 'Marrowby & Vane',  'Cragsley Outfitters', 'Ampfeld Elektronik')ORDER BY visits_per_order ASC, tenant_name ASCORDER BY visits_per_order ASC NULLS LAST, tenant_name ASC NULLS LAST, t.id NULLS LAST
    SELECT
      t.name AS tenant_name,
      t.industry AS industry,
      COALESCE(v.visits_2025, 0) AS visits_2025,
      COALESCE(o.orders_2025, 0) AS orders_2025,
      CAST(COALESCE(v.visits_2025, 0) AS numeric(18,6)) / NULLIF(COALESCE(o.orders_2025, 0), 0) AS visits_per_order,
      100.0 * COALESCE(s.sub_linked_orders, 0) / NULLIF(COALESCE(o.orders_2025, 0), 0) AS subscription_linked_orders_pct,
      COALESCE(a.active_subscriptions, 0) AS active_subscriptions
    FROM tenants t
    LEFT JOIN (
      SELECT tenant_id, COUNT(*) AS visits_2025
      FROM web_sessions
      WHERE started_at >= DATE '2025-01-01' AND started_at < DATE '2026-01-01'
      GROUP BY tenant_id
    ) v ON v.tenant_id = t.id
    LEFT JOIN (
      SELECT tenant_id, COUNT(*) AS orders_2025
      FROM orders
      WHERE placed_at >= DATE '2025-01-01' AND placed_at < DATE '2026-01-01'
      GROUP BY tenant_id
    ) o ON o.tenant_id = t.id
    LEFT JOIN (
      SELECT o2.tenant_id AS tenant_id, COUNT(*) AS sub_linked_orders
      FROM orders o2
      WHERE o2.placed_at >= DATE '2025-01-01' AND o2.placed_at < DATE '2026-01-01'
        AND EXISTS (
          SELECT 1 FROM invoices i
          WHERE i.order_id = o2.id AND i.subscription_id IS NOT NULL
        )
      GROUP BY o2.tenant_id
    ) s ON s.tenant_id = t.id
    LEFT JOIN (
      SELECT tenant_id, COUNT(*) AS active_subscriptions
      FROM subscriptions
      WHERE status = 'active'
      GROUP BY tenant_id
    ) a ON a.tenant_id = t.id
    WHERE t.name IN (
      'Brennquell Kaffee', 'Spice Route Box', 'Grind Collective', 'Honeycomb Larder',
      'Kibblewick', 'Studio Vrij', 'Petalcourt Beauty', 'Marrowby & Vane',
      'Cragsley Outfitters', 'Ampfeld Elektronik'
    )
    ORDER BY visits_per_order ASC NULLS LAST, tenant_name ASC NULLS LAST, t.id NULLS LAST
    10 ms100 ms1 sHyper21.0 msDuckDB75.2 msGizmoSQL83.8 msclickhouse_brew193 msFirebolt126 msDataFusion164 msClickHouse137 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

    Felix's whole session, 7 turns
    • The request, as Felix received it
      Report request from Emeka Obi (analyst for the VP Product):
      
      Title: Session-tracking coverage vs order volume for top merchants, 2025
      Question: Does the >100% visit-to-cart ratio in the Q4 funnel reflect real shopper behavior, or is web-session tracking sparse relative to order volume for certain merchants (e.g. subscription sellers), making 'visits' an unreliable denominator for them?
      Grain: one row per tenant, for the same 10 tenants as the Q4 2025 funnel report
      Columns:
      - tenant name
      - industry
      - visits in 2025 (web_sessions count)
      - orders placed in 2025
      - visits per order
      - subscription-linked orders % (orders with a matching invoice whose subscription_id is not null)
      - active subscriptions (current count, status = active)
      Details: Tenants: Brennquell Kaffee, Spice Route Box, Grind Collective, Honeycomb Larder, Kibblewick, Studio Vrij, Petalcourt Beauty, Marrowby & Vane, Cragsley Outfitters, Ampfeld Elektronik (look up tenant_id by name in tenants; also pull tenants.industry). Visits = count of web_sessions where started_at is in 2025-01-01 to 2025-12-31. Orders = count of orders where placed_at is in 2025-01-01 to 2025-12-31. Visits per order = visits / orders, rounded to 2 decimals. Subscription-linked orders % = among those 2025 orders, the % that have a matching row in invoices (invoices.order_id = orders.id) where invoices.subscription_id is not null, rounded to 1 decimal. Active subscriptions = count of rows in subscriptions for that tenant_id with status = 'active' (current snapshot, no date filter). Order rows by visits_per_order ascending (most session-sparse first), tie-break by tenant name.
      
      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,
        t.industry,
        COALESCE(v.visits_2025, 0) AS visits_2025,
        COALESCE(o.orders_2025, 0) AS orders_2025,
        ROUND(COALESCE(v.visits_2025, 0)::numeric / NULLIF(COALESCE(o.orders_2025, 0), 0), 2) AS visits_per_order,
        ROUND(100.0 * COALESCE(s.sub_linked_orders, 0) / NULLIF(COALESCE(o.orders_2025, 0), 0), 1) AS subscription_linked_orders_pct,
        COALESCE(a.active_subscriptions, 0) AS active_subscriptions
      FROM tenants t
      LEFT JOIN (
        SELECT tenant_id, COUNT(*) AS visits_2025
        FROM web_sessions
        WHERE started_at >= DATE '2025-01-01' AND started_at < DATE '2026-01-01'
        GROUP BY tenant_id
      ) v ON v.tenant_id = t.id
      LEFT JOIN (
        SELECT tenant_id, COUNT(*) AS orders_2025
        FROM orders
        WHERE placed_at >= DATE '2025-01-01' AND placed_at < DATE '2026-01-01'
        GROUP BY tenant_id
      ) o ON o.tenant_id = t.id
      LEFT JOIN (
        SELECT o2.tenant_id, COUNT(*) AS sub_linked_orders
        FROM orders o2
        WHERE o2.placed_at >= DATE '2025-01-01' AND o2.placed_at < DATE '2026-01-01'
          AND EXISTS (
            SELECT 1 FROM invoices i
            WHERE i.order_id = o2.id AND i.subscription_id IS NOT NULL
          )
        GROUP BY o2.tenant_id
      ) s ON s.tenant_id = t.id
      LEFT JOIN (
        SELECT tenant_id, COUNT(*) AS active_subscriptions
        FROM subscriptions
        WHERE status = 'active'
        GROUP BY tenant_id
      ) a ON a.tenant_id = t.id
      WHERE t.name IN (
        'Brennquell Kaffee', 'Spice Route Box', 'Grind Collective', 'Honeycomb Larder',
        'Kibblewick', 'Studio Vrij', 'Petalcourt Beauty', 'Marrowby & Vane',
        'Cragsley Outfitters', 'Ampfeld Elektronik'
      )
      ORDER BY visits_per_order ASC, tenant_name ASC
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: tenant_name, industry, visits_2025, orders_2025, visits_per_order, subscription_linked_orders_pct, active_subscriptions
    • FelixQuery compiles and returns the expected columns. Submitting.
    • Felix calls submit
      SELECT
        t.name AS tenant_name,
        t.industry,
        COALESCE(v.visits_2025, 0) AS visits_2025,
        COALESCE(o.orders_2025, 0) AS orders_2025,
        ROUND(COALESCE(v.visits_2025, 0)::numeric / NULLIF(COALESCE(o.orders_2025, 0), 0), 2) AS visits_per_order,
        ROUND(100.0 * COALESCE(s.sub_linked_orders, 0) / NULLIF(COALESCE(o.orders_2025, 0), 0), 1) AS subscription_linked_orders_pct,
        COALESCE(a.active_subscriptions, 0) AS active_subscriptions
      FROM tenants t
      LEFT JOIN (
        SELECT tenant_id, COUNT(*) AS visits_2025
        FROM web_sessions
        WHERE started_at >= DATE '2025-01-01' AND started_at < DATE '2026-01-01'
        GROUP BY tenant_id
      ) v ON v.tenant_id = t.id
      LEFT JOIN (
        SELECT tenant_id, COUNT(*) AS orders_2025
        FROM orders
        WHERE placed_at >= DATE '2025-01-01' AND placed_at < DATE '2026-01-01'
        GROUP BY tenant_id
      ) o ON o.tenant_id = t.id
      LEFT JOIN (
        SELECT o2.tenant_id, COUNT(*) AS sub_linked_orders
        FROM orders o2
        WHERE o2.placed_at >= DATE '2025-01-01' AND o2.placed_at < DATE '2026-01-01'
          AND EXISTS (
            SELECT 1 FROM invoices i
            WHERE i.order_id = o2.id AND i.subscription_id IS NOT NULL
          )
        GROUP BY o2.tenant_id
      ) s ON s.tenant_id = t.id
      LEFT JOIN (
        SELECT tenant_id, COUNT(*) AS active_subscriptions
        FROM subscriptions
        WHERE status = 'active'
        GROUP BY tenant_id
      ) a ON a.tenant_id = t.id
      WHERE t.name IN (
        'Brennquell Kaffee', 'Spice Route Box', 'Grind Collective', 'Honeycomb Larder',
        'Kibblewick', 'Studio Vrij', 'Petalcourt Beauty', 'Marrowby & Vane',
        'Cragsley Outfitters', 'Ampfeld Elektronik'
      )
      ORDER BY visits_per_order ASC, tenant_name ASC
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • FelixSubmitted. The report gives one row per tenant (the same 10 from the Q4 funnel) with visits, orders, visits-per-order, subscription-linked order share, and current active subscriptions — ordered most session-sparse first, which should directly show whether the inflated visit-to-cart ratio concentrates in subscription-heavy merchants with thin session tracking.