DB Olympics

Queries · q010 · Chief Executive Officer · week 1, night 4

Merchant status and payout activity, today

“What share of our merchant base is actually transacting, and how does that break down by account status?”

Manager · asked the questionMaren OkaforChief Executive Officer. Joined two weeks ago from a European payments company. Board meeting at the end of January.
Analyst · planned the reportHannah BrooksMethodical: starts with an overview, then drills into whatever looks unusual.
Engineer · wrote the SQLGraceWrites tidy, layered CTEs with descriptive names, one step per CTE, then a final select.

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

  1. Maren Okafor writes to Hannah Brooks

    The manager, at the start of week 1

    Subject: A few questions to get me oriented before the board meeting

    Hi Hannah,

    Thanks for taking these on this week — I know slots are tight, so please prioritize in the order below and don't force everything into this week if it doesn't fit cleanly. I'd rather get three solid answers than five rushed ones.

    1. Where does our revenue actually come from? I'd like a sense of how concentrated we are — which merchants and which verticals are driving the bulk of our volume and fees today, and how that's shifted over the last year or so. I'm trying to understand if we're overly dependent on a handful of accounts.
    2. How healthy is our growth? Are we gaining merchants and transaction volume, or is it flat/declining? I'd like to see the trend over the last several quarters, and ideally whether growth is coming from new merchants or from existing ones doing more.
    3. Where do we make our money, and how is that mix changing? Between platform fees and payment processing, I want to understand the balance, and whether one is growing faster than the other.
    4. What's working and what's not, vertical by vertical? I'd like a simple read on which verticals are thriving versus struggling — whether that's measured by growth, retention, or merchant satisfaction, whatever tells the clearest story.
    5. (If time allows) Are there any warning signs I should know about — merchants at risk of leaving, payment or fulfillment problems, support issues — anything that could become a board-level concern if it's not already on my radar.

    What I need this for: I'm building my mental model of the business ahead of the board meeting at the end of January, and I want my first real conversation with the board to show I understand where we're strong, where we're exposed, and what I'm watching closely. Your Friday memo will be the backbone of that.

    Let me know if any of these need narrowing once you've had a look at what's feasible — happy to discuss before you lock in the report requests.

    Thanks, Maren

  2. Hannah Brooks plans the night

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

    Priority 1 is now fully resolved and consistent (corrected vertical report sums to ~€53,186, matching the merchant-level total exactly). Priority 3 is answered as far as the data allows: take rate is stable (~2.5-2.8%, no clear trend), and I've flagged that the platform-plan billing side genuinely isn't modeled in this warehouse. Priority 2 is covered from night 2. For this final night I'm using all 3 slots to close out priority 4 (vertical health) and priority 5 (warning signs), which haven't been touched yet, since they're explicitly what the Friday memo still needs. One thing jumped out while reviewing: the vertical revenue report only found 57 merchants with a settled payout in the trailing 12 months, versus 111 total tenants reported as 'cumulative active merchants' in night 2 (which only used signup date, not actual activity) — that's a big gap worth quantifying directly, since it could mean either a lot of merchants are still ramping up or a lot have gone quiet/churned. I'm building the status/activity report, a vertical-level health report (status mix + support load), and a company-wide operational trend report (payment failures, refunds, tickets, CSAT) to surface any board-level concerns.

    Merchant status and payout activity, today
    Question
    What share of our merchant base is actually transacting, and how does that break down by account status?
    One row per
    tenants.status value
    Columns
    • tenant status
    • tenant count
    • count with a settled payout in the trailing 12 months
    • count with no settled payout in the trailing 12 months
    • share with no recent payout (%)
    • average tenure in days for those with no recent payout (now - created_at, as of 2026-01-05)
  3. Grace 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)
    WITH active_tenants AS (
        SELECT
            id AS tenant_id,
            status AS tenant_status,
            created_at
        FROM tenants
        WHERE deleted_at IS NULL
    ),
    recent_paid_payouts AS (
        SELECT DISTINCT tenant_id
        FROM payouts
        WHERE status = 'paid'
          AND paid_at >= DATE '2025-01-01'
          AND paid_at < DATE '2026-01-01'
    ),
    tenant_payout_flags AS (
        SELECT
            t.tenant_id,
            t.tenant_status,
            t.created_at,
            CASE WHEN p.tenant_id IS NOT NULL THEN 1 ELSE 0 END AS has_recent_payout,
            (DATE '2026-01-05' - CAST(t.created_at AS DATE)) AS tenure_days
        FROM active_tenants t
        LEFT JOIN recent_paid_payouts p
            ON p.tenant_id = t.tenant_id
    )
    SELECT
        tenant_status,
        COUNT(*) AS tenant_count,
        SUM(has_recent_payout) AS with_recent_payout,
        SUM(1 - has_recent_payout) AS without_recent_payout,
        ROUND(100.0 * SUM(1 - has_recent_payout) / COUNT(*), 1) AS pct_without_recent_payout,
        ROUND(AVG(CASE WHEN has_recent_payout = 0 THEN tenure_days END), 1) AS avg_tenure_days_without_payout
    FROM tenant_payout_flags
    GROUP BY tenant_status
    ORDER BY tenant_count DESC, tenant_status ASC

    “This compiles and returns the expected columns. Submitting now.”

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

    “The report has been submitted. It groups all non-deleted tenants by their status, left-joins to settled payouts (status='paid', paid_at in 2025) to flag each tenant as having a recent payout or not, then aggregates to show tenant count, counts with/without recent payout, the share with no recent payout, and the average tenure (in days, as of 2026-01-05) for the no-payout group — ordered by tenant count descending with status as a tie-break.”

  4. The report comes back overnight

    As Hannah Brooks saw it, from the small dataset the agents worked on

    tenant_status | tenant_count | with_recent_payout | without_recent_payout | pct_without_recent_payout | avg_tenure_days_without_payout
    --------------+--------------+--------------------+-----------------------+---------------------------+-------------------------------
    active        |          107 |                105 |                     2 |                       1.9 |                          117.5
    past_due      |            3 |                  3 |                     0 |                       0.0 |                           NULL
    suspended     |            1 |                  1 |                     0 |                       0.0 |                           NULL
    (3 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 q010

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

    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision; AVG over an integer computed as a decimal: AVG(CAST(x AS NUMERIC(18,6)))
    • made explicita selected t.col gets AS col, its standard name made explicit (3×)
    • 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
    WITH active_tenants AS (    SELECT        id AS tenant_id,        status AS tenant_status,        created_at    FROM tenants    WHERE deleted_at IS NULL),recent_paid_payouts AS (    SELECT DISTINCT tenant_id    FROM payouts    WHERE status = 'paid'      AND paid_at >= DATE '2025-01-01'      AND paid_at < DATE '2026-01-01'),tenant_payout_flags AS (    SELECT        t.tenant_id,        t.tenant_status,        t.created_at,        t.tenant_id AS tenant_id,        t.tenant_status AS tenant_status,        t.created_at AS created_at,        CASE WHEN p.tenant_id IS NOT NULL THEN 1 ELSE 0 END AS has_recent_payout,        (DATE '2026-01-05' - CAST(t.created_at AS DATE)) AS tenure_days    FROM active_tenants t    LEFT JOIN recent_paid_payouts p        ON p.tenant_id = t.tenant_id)SELECT    tenant_status,    COUNT(*) AS tenant_count,    SUM(has_recent_payout) AS with_recent_payout,    SUM(1 - has_recent_payout) AS without_recent_payout,    ROUND(100.0 * SUM(1 - has_recent_payout) / COUNT(*), 1) AS pct_without_recent_payout,    ROUND(AVG(CASE WHEN has_recent_payout = 0 THEN tenure_days END), 1) AS avg_tenure_days_without_payout    100.0 * SUM(1 - has_recent_payout) / COUNT(*) AS pct_without_recent_payout,    AVG(CAST(CASE WHEN has_recent_payout = 0 THEN tenure_days END AS NUMERIC(18,6))) AS avg_tenure_days_without_payoutFROM tenant_payout_flagsGROUP BY tenant_statusORDER BY tenant_count DESC, tenant_status ASCORDER BY tenant_count DESC NULLS FIRST, tenant_status ASC NULLS LAST
    WITH active_tenants AS (
        SELECT
            id AS tenant_id,
            status AS tenant_status,
            created_at
        FROM tenants
        WHERE deleted_at IS NULL
    ),
    recent_paid_payouts AS (
        SELECT DISTINCT tenant_id
        FROM payouts
        WHERE status = 'paid'
          AND paid_at >= DATE '2025-01-01'
          AND paid_at < DATE '2026-01-01'
    ),
    tenant_payout_flags AS (
        SELECT
            t.tenant_id AS tenant_id,
            t.tenant_status AS tenant_status,
            t.created_at AS created_at,
            CASE WHEN p.tenant_id IS NOT NULL THEN 1 ELSE 0 END AS has_recent_payout,
            (DATE '2026-01-05' - CAST(t.created_at AS DATE)) AS tenure_days
        FROM active_tenants t
        LEFT JOIN recent_paid_payouts p
            ON p.tenant_id = t.tenant_id
    )
    SELECT
        tenant_status,
        COUNT(*) AS tenant_count,
        SUM(has_recent_payout) AS with_recent_payout,
        SUM(1 - has_recent_payout) AS without_recent_payout,
        100.0 * SUM(1 - has_recent_payout) / COUNT(*) AS pct_without_recent_payout,
        AVG(CAST(CASE WHEN has_recent_payout = 0 THEN tenure_days END AS NUMERIC(18,6))) AS avg_tenure_days_without_payout
    FROM tenant_payout_flags
    GROUP BY tenant_status
    ORDER BY tenant_count DESC NULLS FIRST, tenant_status ASC NULLS LAST
    1 ms10 ms100 msHyper3.7 msDuckDB9.1 msGizmoSQL7.9 msclickhouse_brew33.6 msFirebolt23.5 msDataFusion44.8 msClickHouse8.2 ms
  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

    Grace's whole session, 7 turns
    • The request, as Grace received it
      Report request from Hannah Brooks (analyst for the Chief Executive Officer):
      
      Title: Merchant status and payout activity, today
      Question: What share of our merchant base is actually transacting, and how does that break down by account status?
      Grain: one row per tenants.status value
      Columns:
      - tenant status
      - tenant count
      - count with a settled payout in the trailing 12 months
      - count with no settled payout in the trailing 12 months
      - share with no recent payout (%)
      - average tenure in days for those with no recent payout (now - created_at, as of 2026-01-05)
      Details: Source: tenants left joined to payouts (status='paid', paid_at >= 2025-01-01 and < 2026-01-01) aggregated per tenant_id to a yes/no flag. Group by tenants.status (trial, active, past_due, suspended, churned) and exclude tenants with deleted_at not null. For the tenure column, compute age in days as 2026-01-05 minus tenants.created_at, averaged only over the 'no recent payout' group within each status. Order by tenant count descending, tie-break by status name ascending.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Grace calls dry_run
      WITH active_tenants AS (
          SELECT
              id AS tenant_id,
              status AS tenant_status,
              created_at
          FROM tenants
          WHERE deleted_at IS NULL
      ),
      recent_paid_payouts AS (
          SELECT DISTINCT tenant_id
          FROM payouts
          WHERE status = 'paid'
            AND paid_at >= DATE '2025-01-01'
            AND paid_at < DATE '2026-01-01'
      ),
      tenant_payout_flags AS (
          SELECT
              t.tenant_id,
              t.tenant_status,
              t.created_at,
              CASE WHEN p.tenant_id IS NOT NULL THEN 1 ELSE 0 END AS has_recent_payout,
              (DATE '2026-01-05' - CAST(t.created_at AS DATE)) AS tenure_days
          FROM active_tenants t
          LEFT JOIN recent_paid_payouts p
              ON p.tenant_id = t.tenant_id
      )
      SELECT
          tenant_status,
          COUNT(*) AS tenant_count,
          SUM(has_recent_payout) AS with_recent_payout,
          SUM(1 - has_recent_payout) AS without_recent_payout,
          ROUND(100.0 * SUM(1 - has_recent_payout) / COUNT(*), 1) AS pct_without_recent_payout,
          ROUND(AVG(CASE WHEN has_recent_payout = 0 THEN tenure_days END), 1) AS avg_tenure_days_without_payout
      FROM tenant_payout_flags
      GROUP BY tenant_status
      ORDER BY tenant_count DESC, tenant_status ASC
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: tenant_status, tenant_count, with_recent_payout, without_recent_payout, pct_without_recent_payout, avg_tenure_days_without_payout
    • GraceThis compiles and returns the expected columns. Submitting now.
    • Grace calls submit
      WITH active_tenants AS (
          SELECT
              id AS tenant_id,
              status AS tenant_status,
              created_at
          FROM tenants
          WHERE deleted_at IS NULL
      ),
      recent_paid_payouts AS (
          SELECT DISTINCT tenant_id
          FROM payouts
          WHERE status = 'paid'
            AND paid_at >= DATE '2025-01-01'
            AND paid_at < DATE '2026-01-01'
      ),
      tenant_payout_flags AS (
          SELECT
              t.tenant_id,
              t.tenant_status,
              t.created_at,
              CASE WHEN p.tenant_id IS NOT NULL THEN 1 ELSE 0 END AS has_recent_payout,
              (DATE '2026-01-05' - CAST(t.created_at AS DATE)) AS tenure_days
          FROM active_tenants t
          LEFT JOIN recent_paid_payouts p
              ON p.tenant_id = t.tenant_id
      )
      SELECT
          tenant_status,
          COUNT(*) AS tenant_count,
          SUM(has_recent_payout) AS with_recent_payout,
          SUM(1 - has_recent_payout) AS without_recent_payout,
          ROUND(100.0 * SUM(1 - has_recent_payout) / COUNT(*), 1) AS pct_without_recent_payout,
          ROUND(AVG(CASE WHEN has_recent_payout = 0 THEN tenure_days END), 1) AS avg_tenure_days_without_payout
      FROM tenant_payout_flags
      GROUP BY tenant_status
      ORDER BY tenant_count DESC, tenant_status ASC
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • GraceThe report has been submitted. It groups all non-deleted tenants by their `status`, left-joins to settled payouts (`status='paid'`, `paid_at` in 2025) to flag each tenant as having a recent payout or not, then aggregates to show tenant count, counts with/without recent payout, the share with no recent payout, and the average tenure (in days, as of 2026-01-05) for the no-payout group — ordered by tenant count descending with status as a tie-break.