DB Olympics

Queries · q252 · VP Customer Experience · week 2, night 3

Urgent-ticket resolution-time distribution, slow merchants vs a fast baseline

“Is the big three's inflated average urgent resolution time caused by a handful of extreme-delay tickets, or by generally slow handling across the board?”

Manager · asked the questionDaniel AchterbergVP Customer Experience. Former head of support at a marketplace. Merchants run their helpdesk on Tidewick, so their shoppers' experience is partly Tidewick's reputation.
Analyst · planned the reportMateo RuizComparative: likes year-over-year and peer comparisons across merchants and countries.
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. Daniel Achterberg writes to Mateo Ruiz

    The manager, at the start of week 2

    Subject: Good progress — now I want to understand the "why" behind the hotspots

    Mateo — this is exactly the kind of baseline I needed, thank you. Two things from your memo and Mia's notes are sitting with me:

    First, the speed→satisfaction link is strong and now confirmed two ways (yours and Mia's numbers line up almost exactly), so I believe it. But I don't yet know if slowness causes the dissatisfaction or if the worst merchants are simply worse across the board (harder products, different shopper expectations, something else) and speed is just the symptom we can see. That matters a lot for what I recommend as the fix.

    Second, Mia's finding that three merchants account for a third of all tickets and the worst response times lines up with what you found independently — that's a strong signal, not a coincidence, and it's where I want to spend our next slots.

    Questions for this week:

    1. What's actually different about how Cragsley, Marrowby, and Studio Vrij run their support compared to the rest of the book — are they understaffed relative to their ticket volume, leaning on slower channels, getting hit with harder/more complex issues, or something else? I want to know if this is something we can fix with guidance or tooling, or if it's specific to each merchant's situation.
    2. Is the urgent-priority failure (missing resolution half the time) concentrated in those same few merchants, or is it a broader pattern across the book? If urgent tickets are failing everywhere, that's a different and more worrying problem than a handful of struggling merchants.
    3. Has Studio Vrij actually recovered since the spring breakdown, and what would it take to get ahead of the Nov/Dec pattern this year before it hits? I'd like to walk into December with a plan, not another postmortem.
    4. Before I take "respond faster" to merchants as the headline fix, can we check whether the slowest merchants differ in other ways (ticket mix, how support is staffed, shopper profile) that might also explain their low satisfaction? I don't want to oversimplify the story if something else is going on underneath.

    Let's prioritize #1 and #2 this week — those feel most actionable. #3 and #4 can wait if slots are tight.

    Thanks, Daniel

  2. Mateo Ruiz plans the night

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

    Night 2 results are decisive on complexity: Cragsley (1.36 tags/ticket, 3.46 messages/ticket) and Marrowby (1.43, 3.29) are actually at the LOW end of complexity among all 22 qualifying merchants - Studio Vrij is mid-pack (1.64, 3.71). So "harder issues" is refuted as an explanation; it really does look like a volume/staffing story. The SLA-target report also refutes the "unrealistic target" theory for the broad urgent-miss problem - every merchant evaluated uses the identical 8-hour urgent target, so the wide spread in miss rates (14%-100%) reflects genuine differences in execution speed, not target calibration. The quarterly load report is the key new finding: all three hotspots (and comparison peer Grind Collective) run a completely flat agent headcount all four quarters, but ticket volume surges hard in specific quarters - Cragsley and Marrowby both spike in Q4 (tickets-per-agent roughly doubles vs Q1-Q3), Studio Vrij spikes specifically in Q2 (the already-known fulfillment incident), and Grind Collective also spikes in Q4 even harder than Cragsley. That's a strong lead: nobody scales support staff for volume surges, and it's not unique to the three named merchants. I want to (1) confirm urgent-ticket performance specifically degrades in the same quarters where each merchant's load spiked (a within-merchant causal test), (2) check whether this "flat staffing through a seasonal/incident surge" pattern is common across the whole qualifying book, not just these four - that determines if it's a platform-level guidance opportunity, and (3) characterize whether the big three's inflated average (vs. median) urgent resolution time is a few catastrophic outlier tickets or generally slow handling, since that changes what the fix would look like (triage/escalation vs. core speed).

    Urgent-ticket resolution-time distribution, slow merchants vs a fast baseline
    Question
    Is the big three's inflated average urgent resolution time caused by a handful of extreme-delay tickets, or by generally slow handling across the board?
    One row per
    tenant, for Cragsley Outfitters, Marrowby & Vane, Studio Vrij, Grind Collective, and Wiesgrund Wohnen (included as a fast-performing baseline), urgent-priority tickets only, 2025
    Columns
    • merchant name
    • urgent tickets evaluated
    • % resolved within 8h (meets target)
    • % resolved 8-24h
    • % resolved 1-3 days
    • % resolved 3-7 days
    • % resolved after 7 days or still unresolved as of 2025-12-31
  3. 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 merchant_name,
      COUNT(*) AS urgent_tickets_evaluated,
      ROUND(100.0 * SUM(CASE WHEN b.bucket = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_within_8h,
      ROUND(100.0 * SUM(CASE WHEN b.bucket = 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_8h_24h,
      ROUND(100.0 * SUM(CASE WHEN b.bucket = 3 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1d_3d,
      ROUND(100.0 * SUM(CASE WHEN b.bucket = 4 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_3d_7d,
      ROUND(100.0 * SUM(CASE WHEN b.bucket = 5 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_over_7d_or_unresolved
    FROM (
      SELECT
        tk.id,
        tk.tenant_id,
        CASE
          WHEN tk.resolved_at IS NULL THEN 5
          WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 8 THEN 1
          WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 24 THEN 2
          WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 72 THEN 3
          WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 168 THEN 4
          ELSE 5
        END AS bucket
      FROM tickets tk
      JOIN sla_policies sp ON sp.id = tk.sla_policy_id
      WHERE tk.priority = 'urgent'
        AND tk.sla_policy_id IS NOT NULL
        AND tk.created_at >= timestamp '2025-01-01'
        AND tk.created_at < timestamp '2026-01-01'
        AND tk.tenant_id IN (
          SELECT id FROM tenants
          WHERE name IN ('Cragsley Outfitters', 'Marrowby & Vane', 'Studio Vrij', 'Grind Collective', 'Wiesgrund Wohnen')
        )
    ) b
    JOIN tenants t ON t.id = b.tenant_id
    GROUP BY t.name
    ORDER BY t.name ASC

    “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 (5 rows, ordered by merchant name) with urgent-ticket counts and the five resolution-time bucket percentages for 2025, as specified.”

  4. The report comes back overnight

    As Mateo Ruiz saw it, from the small dataset the agents worked on

    merchant_name       | urgent_tickets_evaluated | pct_within_8h | pct_8h_24h | pct_1d_3d | pct_3d_7d | pct_over_7d_or_unresolved
    --------------------+--------------------------+---------------+------------+-----------+-----------+--------------------------
    Cragsley Outfitters |                       50 |          34.0 |       34.0 |      18.0 |      10.0 |                       4.0
    Grind Collective    |                        6 |          83.3 |       16.7 |       0.0 |       0.0 |                       0.0
    Marrowby & Vane     |                       33 |          33.3 |       18.2 |       9.1 |      18.2 |                      21.2
    Studio Vrij         |                       11 |          36.4 |       18.2 |      27.3 |       0.0 |                      18.2
    Wiesgrund Wohnen    |                        7 |          85.7 |       14.3 |       0.0 |       0.0 |                       0.0
    (5 rows)
  5. 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:

  6. It becomes benchmark query q252

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

    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • numericsdocs/NUMERICS.md: EXTRACT(EPOCH FROM (b - a)) cast to NUMERIC(18,6) (4×)
    • made explicita selected t.col gets AS col, its standard name made explicit (2×)
    • placeholderseconds between (4×)
    • determinismthe standard leaves the place of NULLs in a sort to the implementation: NULLS LAST ascending, NULLS FIRST descending, as in the reference results
    The benchmark text, against the submitted SQL
    SELECT  t.name AS merchant_name,  COUNT(*) AS urgent_tickets_evaluated,  ROUND(100.0 * SUM(CASE WHEN b.bucket = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_within_8h,  ROUND(100.0 * SUM(CASE WHEN b.bucket = 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_8h_24h,  ROUND(100.0 * SUM(CASE WHEN b.bucket = 3 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1d_3d,  ROUND(100.0 * SUM(CASE WHEN b.bucket = 4 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_3d_7d,  ROUND(100.0 * SUM(CASE WHEN b.bucket = 5 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_over_7d_or_unresolved  100.0 * SUM(CASE WHEN b.bucket = 1 THEN 1 ELSE 0 END) / COUNT(*) AS pct_within_8h,  100.0 * SUM(CASE WHEN b.bucket = 2 THEN 1 ELSE 0 END) / COUNT(*) AS pct_8h_24h,  100.0 * SUM(CASE WHEN b.bucket = 3 THEN 1 ELSE 0 END) / COUNT(*) AS pct_1d_3d,  100.0 * SUM(CASE WHEN b.bucket = 4 THEN 1 ELSE 0 END) / COUNT(*) AS pct_3d_7d,  100.0 * SUM(CASE WHEN b.bucket = 5 THEN 1 ELSE 0 END) / COUNT(*) AS pct_over_7d_or_unresolvedFROM (  SELECT    tk.id,    tk.tenant_id,    tk.id AS id,    tk.tenant_id AS tenant_id,    CASE      WHEN tk.resolved_at IS NULL THEN 5      WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 8 THEN 1      WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 24 THEN 2      WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 72 THEN 3      WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 168 THEN 4      WHEN {{seconds_between(tk.created_at, tk.resolved_at)}} / 3600.0 <= 8 THEN 1      WHEN {{seconds_between(tk.created_at, tk.resolved_at)}} / 3600.0 <= 24 THEN 2      WHEN {{seconds_between(tk.created_at, tk.resolved_at)}} / 3600.0 <= 72 THEN 3      WHEN {{seconds_between(tk.created_at, tk.resolved_at)}} / 3600.0 <= 168 THEN 4      ELSE 5    END AS bucket  FROM tickets tk  JOIN sla_policies sp ON sp.id = tk.sla_policy_id  WHERE tk.priority = 'urgent'    AND tk.sla_policy_id IS NOT NULL    AND tk.created_at >= timestamp '2025-01-01'    AND tk.created_at < timestamp '2026-01-01'    AND tk.tenant_id IN (      SELECT id FROM tenants      WHERE name IN ('Cragsley Outfitters', 'Marrowby & Vane', 'Studio Vrij', 'Grind Collective', 'Wiesgrund Wohnen')    )) bJOIN tenants t ON t.id = b.tenant_idGROUP BY t.nameORDER BY t.name ASCORDER BY t.name ASC NULLS LAST
    SELECT
      t.name AS merchant_name,
      COUNT(*) AS urgent_tickets_evaluated,
      100.0 * SUM(CASE WHEN b.bucket = 1 THEN 1 ELSE 0 END) / COUNT(*) AS pct_within_8h,
      100.0 * SUM(CASE WHEN b.bucket = 2 THEN 1 ELSE 0 END) / COUNT(*) AS pct_8h_24h,
      100.0 * SUM(CASE WHEN b.bucket = 3 THEN 1 ELSE 0 END) / COUNT(*) AS pct_1d_3d,
      100.0 * SUM(CASE WHEN b.bucket = 4 THEN 1 ELSE 0 END) / COUNT(*) AS pct_3d_7d,
      100.0 * SUM(CASE WHEN b.bucket = 5 THEN 1 ELSE 0 END) / COUNT(*) AS pct_over_7d_or_unresolved
    FROM (
      SELECT
        tk.id AS id,
        tk.tenant_id AS tenant_id,
        CASE
          WHEN tk.resolved_at IS NULL THEN 5
          WHEN CAST(EXTRACT(EPOCH FROM (tk.resolved_at - tk.created_at)) AS NUMERIC(18,6)) / 3600.0 <= 8 THEN 1
          WHEN CAST(EXTRACT(EPOCH FROM (tk.resolved_at - tk.created_at)) AS NUMERIC(18,6)) / 3600.0 <= 24 THEN 2
          WHEN CAST(EXTRACT(EPOCH FROM (tk.resolved_at - tk.created_at)) AS NUMERIC(18,6)) / 3600.0 <= 72 THEN 3
          WHEN CAST(EXTRACT(EPOCH FROM (tk.resolved_at - tk.created_at)) AS NUMERIC(18,6)) / 3600.0 <= 168 THEN 4
          ELSE 5
        END AS bucket
      FROM tickets tk
      JOIN sla_policies sp ON sp.id = tk.sla_policy_id
      WHERE tk.priority = 'urgent'
        AND tk.sla_policy_id IS NOT NULL
        AND tk.created_at >= timestamp '2025-01-01'
        AND tk.created_at < timestamp '2026-01-01'
        AND tk.tenant_id IN (
          SELECT id FROM tenants
          WHERE name IN ('Cragsley Outfitters', 'Marrowby & Vane', 'Studio Vrij', 'Grind Collective', 'Wiesgrund Wohnen')
        )
    ) b
    JOIN tenants t ON t.id = b.tenant_id
    GROUP BY t.name
    ORDER BY t.name ASC NULLS LAST
    1 ms10 ms100 msHyper5.8 msDuckDB9.1 msGizmoSQL13.1 msclickhouse_brew63.0 msFirebolt68.0 msDataFusionwrong resultClickHouse52.9 ms
    • DataFusionrow 3: col 5: "11.3264338432358883437100564878571723085804" vs "11.33055704448934"; col 6: "10.4523151775038139611594441924710345111945" vs "10.44819197625036"
  7. 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 Mateo Ruiz (analyst for the VP Customer Experience):
      
      Title: Urgent-ticket resolution-time distribution, slow merchants vs a fast baseline
      Question: Is the big three's inflated average urgent resolution time caused by a handful of extreme-delay tickets, or by generally slow handling across the board?
      Grain: one row per tenant, for Cragsley Outfitters, Marrowby & Vane, Studio Vrij, Grind Collective, and Wiesgrund Wohnen (included as a fast-performing baseline), urgent-priority tickets only, 2025
      Columns:
      - merchant name
      - urgent tickets evaluated
      - % resolved within 8h (meets target)
      - % resolved 8-24h
      - % resolved 1-3 days
      - % resolved 3-7 days
      - % resolved after 7 days or still unresolved as of 2025-12-31
      Details: Source: tickets (priority='urgent') joined to sla_policies via tickets.sla_policy_id, filtered to the five named tenants. Window: tickets.created_at in 2025-01-01 through 2025-12-31, excluding tickets with null sla_policy_id (same evaluable definition as prior reports). resolution_hours = extract(epoch from resolved_at - created_at)/3600 for tickets with resolved_at not null; tickets with resolved_at null as of 2025-12-31 fall into the last bucket ('after 7 days or still unresolved') regardless of elapsed time. Bucket boundaries: <=8h, >8-24h, >24-72h (1-3 days), >72-168h (3-7 days), >168h or unresolved. Each tenant's five percentages should sum to ~100 (rounded to 1 decimal each). Order by merchant name ascending. Expect exactly 5 rows.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Felix calls dry_run
      SELECT
        t.name AS merchant_name,
        COUNT(*) AS urgent_tickets_evaluated,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_within_8h,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_8h_24h,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 3 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1d_3d,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 4 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_3d_7d,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 5 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_over_7d_or_unresolved
      FROM (
        SELECT
          tk.id,
          tk.tenant_id,
          CASE
            WHEN tk.resolved_at IS NULL THEN 5
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 8 THEN 1
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 24 THEN 2
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 72 THEN 3
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 168 THEN 4
            ELSE 5
          END AS bucket
        FROM tickets tk
        JOIN sla_policies sp ON sp.id = tk.sla_policy_id
        WHERE tk.priority = 'urgent'
          AND tk.sla_policy_id IS NOT NULL
          AND tk.created_at >= timestamp '2025-01-01'
          AND tk.created_at < timestamp '2026-01-01'
          AND tk.tenant_id IN (
            SELECT id FROM tenants
            WHERE name IN ('Cragsley Outfitters', 'Marrowby & Vane', 'Studio Vrij', 'Grind Collective', 'Wiesgrund Wohnen')
          )
      ) b
      JOIN tenants t ON t.id = b.tenant_id
      GROUP BY t.name
      ORDER BY t.name ASC
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: merchant_name, urgent_tickets_evaluated, pct_within_8h, pct_8h_24h, pct_1d_3d, pct_3d_7d, pct_over_7d_or_unresolved
    • FelixQuery compiles cleanly with the expected columns. Submitting.
    • Felix calls submit
      SELECT
        t.name AS merchant_name,
        COUNT(*) AS urgent_tickets_evaluated,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_within_8h,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_8h_24h,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 3 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1d_3d,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 4 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_3d_7d,
        ROUND(100.0 * SUM(CASE WHEN b.bucket = 5 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_over_7d_or_unresolved
      FROM (
        SELECT
          tk.id,
          tk.tenant_id,
          CASE
            WHEN tk.resolved_at IS NULL THEN 5
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 8 THEN 1
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 24 THEN 2
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 72 THEN 3
            WHEN extract(epoch FROM tk.resolved_at - tk.created_at) / 3600.0 <= 168 THEN 4
            ELSE 5
          END AS bucket
        FROM tickets tk
        JOIN sla_policies sp ON sp.id = tk.sla_policy_id
        WHERE tk.priority = 'urgent'
          AND tk.sla_policy_id IS NOT NULL
          AND tk.created_at >= timestamp '2025-01-01'
          AND tk.created_at < timestamp '2026-01-01'
          AND tk.tenant_id IN (
            SELECT id FROM tenants
            WHERE name IN ('Cragsley Outfitters', 'Marrowby & Vane', 'Studio Vrij', 'Grind Collective', 'Wiesgrund Wohnen')
          )
      ) b
      JOIN tenants t ON t.id = b.tenant_id
      GROUP BY t.name
      ORDER BY t.name ASC
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • FelixSubmitted. The report returns one row per tenant (5 rows, ordered by merchant name) with urgent-ticket counts and the five resolution-time bucket percentages for 2025, as specified.