DB Olympics

Queries · q149 · Head of Pricing and Promotions · week 1, night 1

Discount spend concentration by tenant and vertical, 2025

“Are one or two merchants (or one vertical) responsible for most of our discount spend, relative to their share of revenue?”

Manager · asked the questionMarco BianchiHead of Pricing and Promotions. Previously in revenue management at a travel company.
Analyst · planned the reportOliver GrantPeer-minded: compares each merchant with peers of similar size and vertical.
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. A business event lands on the Head of Pricing and Promotions's desk

    Week 1; shared with Tobias Lindqvist, Chief Financial Officer

    Finance questions the cost of discounts. Which promotions and coupons brought additional sales, which only gave away margin, and is anything being misused?

  2. Marco Bianchi writes to Oliver Grant

    The manager, at the start of week 1

    Subject: Priorities for this week's discount cost-review with Tobias

    Oliver,

    Tobias and I need a credible answer to "are our promotions and coupons earning their keep," in time for Friday's memo. This feeds a joint decision on which promotions/coupons we keep, retire, or cap going into next quarter — so I'd rather have four solid, well-checked answers than a pile of rushed ones. Please pick the nights' reports accordingly and flag anything suspicious you find along the way rather than burying it in a footnote.

    Here's what I actually want to know, in my own words:

    1. Which promotions and coupons are costing us the most, and is that cost buying us anything? I want to see discount cost alongside the orders/revenue they sit on, so we can tell "big spend, big lift" apart from "big spend, no lift."
    2. For our top discounts, do customers actually spend more because of them, or are we just discounting purchases that would have happened anyway? I know this is the hard one — I just want our best honest read on it, even if approximate.
    3. Are any coupons being overused or abused — the same customers redeeming repeatedly, usage patterns that look like stacking or sharing of codes meant to be one-time or limited, or codes that are far outliving the campaign they were meant for?
    4. Which discounts are quietly eating into margin on top of their price reduction — for example cases where returns or refunds cluster around discounted orders, so the real cost is higher than the discount line alone suggests.
    5. (If there's a slot left) How does this differ by merchant or vertical — are one or two tenants responsible for most of the discount spend, which would change how we approach this.

    Keep each report to one clear question — I'd rather get three clean answers this week than one bundled one that gets bounced. Let's sync briefly before you submit Thursday's batch in case the first results change what we ask.

    Thanks, Marco

    A note from the Chief Financial Officer, Tobias Lindqvist

    Subject: Finance's angle on the promotions/coupons review

    Oliver,

    As you and Marco dig into discount performance this week, a few things I'd like the analysis to keep an eye on from the finance side:

    1. Are discounted orders actually incremental, or just margin we're giving away on sales that would have happened anyway? I care less about redemption volume and more about whether promotions are growing net revenue after the discount, versus simply lowering what we collect on existing demand.
    2. Is any of this exposed as cost we haven't fully absorbed yet? Where coupons stack with refunds or returns, I want to understand whether we're left carrying a loss after the fact, especially heading into year-end close.
    3. Is there any pattern of abuse or concentration — the same accounts or a narrow set of merchants repeatedly running the heaviest discounts — that's quietly eating into margin rather than driving genuine growth?

    Keep it tight; I mainly need the "so what" for the annual accounts and the 2026 budget assumptions on discount cost.

    Thanks, Tobias

  3. Oliver Grant plans the night

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

    Marco and Tobias both want: (1) cost vs. lift per discount, (2) incrementality read, (3) abuse/concentration signals, (4) margin erosion via returns/refunds, (5) merchant/vertical concentration. That's 5 questions but only 3 slots tonight, so I'm front-loading the foundational, non-overlapping pieces that everything else will build on, and saving the harder incrementality/refund-overlap asks for later nights once I've seen where the money actually sits:

    1. A discount-level cost-vs-lift report (answers Marco Q1) — this is the spine of the whole review.
    2. A tenant/vertical concentration report (answers Marco Q5 / Tobias Q3 concentration) — I want this early because it tells me whether the Q1 rankings are really "a few big promotions" or "a few big merchants," which changes how I read everything else.
    3. A coupon-level abuse/misuse report (answers Marco Q3 / Tobias Q3 abuse) — distinct customers, repeat redemption, limit violations, post-expiry usage, since this is a pure redemption-pattern question independent of revenue lift.

    I'm holding off on incrementality (Q2) and returns/refund leakage (Q4) until I see which discounts and tenants actually matter — no point building a careful before/after spend comparison for a promotion that turns out to be trivial. All three reports use 2025 full-year data (most relevant to the 2026 budget conversation) with amounts converted to EUR via exchange_rates so merchants in different currencies are comparable.

    Discount spend concentration by tenant and vertical, 2025
    Question
    Are one or two merchants (or one vertical) responsible for most of our discount spend, relative to their share of revenue?
    One row per
    tenant
    Columns
    • tenant name
    • vertical (tenants.industry)
    • total discount amount (EUR)
    • total order revenue, grand_total (EUR)
    • discount amount as % of order revenue
    • order count
    • distinct discount codes/coupons used
    • share of company-wide discount spend (%)
  4. 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 eligible_orders AS (
        SELECT
            o.id AS order_id,
            o.tenant_id,
            o.grand_total,
            o.currency_code,
            o.placed_at
        FROM orders o
        WHERE o.placed_at >= DATE '2025-01-01'
          AND o.placed_at < DATE '2026-01-01'
          AND o.status <> 'cancelled'
    ),
    order_revenue_eur AS (
        SELECT
            eo.tenant_id,
            eo.order_id,
            eo.grand_total / er.rate AS revenue_eur
        FROM eligible_orders eo
        JOIN exchange_rates er
          ON er.base_code = 'EUR'
         AND er.quote_code = eo.currency_code
         AND er.as_of = DATE(eo.placed_at)
    ),
    tenant_order_totals AS (
        SELECT
            tenant_id,
            SUM(revenue_eur) AS total_revenue_eur,
            COUNT(DISTINCT order_id) AS order_count
        FROM order_revenue_eur
        GROUP BY tenant_id
    ),
    discount_detail AS (
        SELECT
            od.tenant_id,
            od.order_id,
            od.amount / er.rate AS discount_eur,
            COALESCE(od.coupon_id::varchar, od.code) AS discount_code_key
        FROM order_discounts od
        JOIN eligible_orders eo
          ON eo.order_id = od.order_id
         AND eo.tenant_id = od.tenant_id
        JOIN exchange_rates er
          ON er.base_code = 'EUR'
         AND er.quote_code = od.currency_code
         AND er.as_of = DATE(eo.placed_at)
    ),
    tenant_discount_totals AS (
        SELECT
            tenant_id,
            SUM(discount_eur) AS total_discount_eur,
            COUNT(DISTINCT discount_code_key) AS distinct_discount_codes
        FROM discount_detail
        GROUP BY tenant_id
    ),
    combined AS (
        SELECT
            t.name AS tenant_name,
            t.industry AS vertical,
            COALESCE(td.total_discount_eur, 0) AS discount_eur,
            ot.total_revenue_eur AS revenue_eur,
            ot.order_count,
            COALESCE(td.distinct_discount_codes, 0) AS distinct_discount_codes
        FROM tenant_order_totals ot
        JOIN tenants t ON t.id = ot.tenant_id
        LEFT JOIN tenant_discount_totals td ON td.tenant_id = ot.tenant_id
    )
    SELECT
        tenant_name,
        vertical,
        ROUND(discount_eur, 2) AS discount_amount_eur,
        ROUND(revenue_eur, 2) AS order_revenue_eur,
        ROUND(discount_eur / NULLIF(revenue_eur, 0) * 100, 2) AS discount_pct_of_revenue,
        order_count,
        distinct_discount_codes,
        ROUND(discount_eur / NULLIF(SUM(discount_eur) OVER (), 0) * 100, 2) AS share_of_company_discount_pct
    FROM combined
    ORDER BY discount_amount_eur DESC, tenant_name
    LIMIT 50

    “Query compiles cleanly with the expected 8 columns. Submitting.”

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

    “Submitted. Summary of the approach: - Base population: all non-cancelled orders with placed_at in 2025, per tenant. - Revenue: grand_total converted to EUR day-by-day via exchange_rates (EUR→local rate, so divide to get EUR). - Discounts: order_discounts.amount converted to EUR the same way, joined only to orders in the 2025 eligible set. - Distinct codes: counts distinct coupon_id (falling back to the free-text code when no coupon is linked). - Share of company spend: each tenant's EUR discount total divided by the window sum across all tenants. - Tenants with no discounts still appear (discount = 0, share = 0) so the "concentration" picture is complete; sorted by discount EUR descending, top 50 printed, as requested.”

  5. The report comes back overnight

    As Oliver Grant saw it, from the small dataset the agents worked on

    tenant_name            | vertical                  | discount_amount_eur | order_revenue_eur | discount_pct_of_revenue | order_count | distinct_discount_codes | share_of_company_discount_pct
    -----------------------+---------------------------+---------------------+-------------------+-------------------------+-------------+-------------------------+------------------------------
    Castell Fasteners      | Industrial Supplies (B2B) |            26831.67 |         376053.99 |                    7.14 |         156 |                       1 |                         15.93
    Grind Collective       | Food & Coffee             |            24713.89 |          24732.45 |                   99.92 |        1094 |                       2 |                         14.67
    Honeycomb Larder       | Food & Coffee             |            16642.16 |          17169.59 |                   96.93 |         610 |                       1 |                          9.88
    Cragsley Outfitters    | Apparel & Footwear        |            14744.05 |         695715.59 |                    2.12 |        3486 |                       1 |                          8.75
    OfficeHub Nordic       | Office Supplies (B2B)     |            14406.96 |         399338.22 |                    3.61 |         167 |                       1 |                          8.55
    Marrowby & Vane        | Apparel & Footwear        |            13433.31 |          275390.8 |                    4.88 |        1674 |                       1 |                          7.97
    Deskline Supplies      | Office Supplies (B2B)     |            13387.76 |         285178.35 |                    4.69 |          75 |                       1 |                          7.95
    Kibblewick             | Pet Supplies              |            12185.44 |          22531.09 |                   54.08 |         651 |                       2 |                          7.23
    Cinder Peak Sports Co. | Sports & Outdoor          |             9072.94 |         122664.88 |                     7.4 |         328 |                       2 |                          5.39
    Feather & Fin          | Pet Supplies              |             5729.19 |           6695.71 |                   85.57 |         215 |                       2 |                           3.4
    Saffron & Sage         | Beauty                    |             4567.44 |           6674.76 |                   68.43 |         113 |                       1 |                          2.71
    Fennel & Flint         | Home & Living             |             1743.03 |          64080.39 |                    2.72 |         379 |                       2 |                          1.03
    The Balm Room          | Beauty                    |             1601.58 |          12420.47 |                   12.89 |         101 |                       1 |                          0.95
    Petalcourt Beauty      | Beauty                    |             1395.12 |          60927.41 |                    2.29 |         674 |                       2 |                          0.83
    Oakhurst Tailoring     | Apparel & Footwear        |              934.85 |          24024.22 |                    3.89 |         155 |                       2 |                          0.55
    Coastline Interiors    | Home & Living             |              784.96 |          20669.23 |                     3.8 |         149 |                       2 |                          0.47
    Thistlecombe           | Apparel & Footwear        |              654.88 |          11735.12 |                    5.58 |          87 |                       2 |                          0.39
    Bytefield              | Consumer Electronics      |              519.74 |          12458.03 |                    4.17 |          22 |                       2 |                          0.31
    Kayak Corner           | Sports & Outdoor          |              498.56 |          39065.09 |                    1.28 |         101 |                       1 |                           0.3
    Velvet Ash             | Apparel & Footwear        |              455.74 |          23591.19 |                    1.93 |         130 |                       1 |                          0.27
    Juniper Apothecary     | Beauty                    |               430.8 |          17051.87 |                    2.53 |         149 |                       2 |                          0.26
    Willow & Wren          | Home & Living             |              428.74 |          18796.06 |                    2.28 |          95 |                       2 |                          0.25
    Nordic Bloom Cosmetics | Beauty                    |              415.68 |           16425.2 |                    2.53 |         135 |                       2 |                          0.25
    Lamplight Living       | Home & Living             |              348.96 |           6630.61 |                    5.26 |          48 |                       2 |                          0.21
    Stoneware Studio       | Home & Living             |              292.65 |           2952.89 |                    9.91 |          25 |                       1 |                          0.17
    Alpine Loft            | Sports & Outdoor          |              244.84 |           2430.37 |                   10.07 |           2 |                       1 |                          0.15
    Circuit Harbor         | Consumer Electronics      |              231.12 |          18806.68 |                    1.23 |          18 |                       2 |                          0.14
    The Pencil Case        | Books & Stationery        |              202.82 |             25.95 |                  781.56 |           4 |                       0 |                          0.12
    Courtside Collective   | Sports & Outdoor          |              180.61 |           6639.97 |                    2.72 |          19 |                       2 |                          0.11
    Brick & Bobbin         | Apparel & Footwear        |              143.94 |           3589.13 |                    4.01 |          25 |                       2 |                          0.09
    Hus & Hem              | Home & Living             |              131.24 |           5173.25 |                    2.54 |          34 |                       2 |                          0.08
    Silverthread           | Jewelry & Accessories     |              115.19 |           3001.87 |                    3.84 |          13 |                       2 |                          0.07
    Roast Republic         | Food & Coffee             |              111.36 |           5488.11 |                    2.03 |          51 |                       2 |                          0.07
    Little Larch Kids      | Apparel & Footwear        |              105.05 |           2582.94 |                    4.07 |          22 |                       2 |                          0.06
    Rosehip Lab            | Beauty                    |              100.13 |            2857.4 |                     3.5 |          29 |                       2 |                          0.06
    Haven Linen            | Home & Living             |               88.97 |           3993.52 |                    2.23 |          24 |                       2 |                          0.05
    Signalbox              | Consumer Electronics      |               80.36 |           1439.85 |                    5.58 |           5 |                       1 |                          0.05
    Meadow Row             | Apparel & Footwear        |               60.31 |           9825.26 |                    0.61 |          24 |                       1 |                          0.04
    Glasshouse Grooming    | Beauty                    |               57.73 |           1397.46 |                    4.13 |           9 |                       2 |                          0.03
    Fell & Fjell           | Sports & Outdoor          |               57.53 |          35677.12 |                    0.16 |          79 |                       1 |                          0.03
    Purrfect Pantry        | Pet Supplies              |               57.41 |           3543.62 |                    1.62 |          73 |                       2 |                          0.03
    Barkley & Co.          | Pet Supplies              |               49.37 |           2740.46 |                     1.8 |          36 |                       1 |                          0.03
    Snout & Sons           | Pet Supplies              |                41.9 |            383.16 |                   10.93 |           7 |                       1 |                          0.02
    Fjordline Wear         | Apparel & Footwear        |               38.24 |           7915.46 |                    0.48 |          54 |                       1 |                          0.02
    Greyfriars Supply      | Apparel & Footwear        |               32.84 |            3149.4 |                    1.04 |          14 |                       2 |                          0.02
    Tail Wag Supply        | Pet Supplies              |               19.74 |           5728.03 |                    0.34 |          89 |                       1 |                          0.01
    Tiny Atelier           | Home & Living             |               17.35 |           3750.14 |                    0.46 |          32 |                       1 |                          0.01
    Teapot Society         | Food & Coffee             |               14.51 |             78.81 |                   18.41 |           1 |                       1 |                          0.01
    Olive & Oak Pantry     | Food & Coffee             |               12.05 |            118.55 |                   10.17 |           1 |                       1 |                          0.01
    Folio & Fern           | Books & Stationery        |               11.02 |           1963.85 |                    0.56 |          43 |                       1 |                          0.01
    (50 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:

  7. It becomes benchmark query q149

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

    • spellingcast
    • spellingfetch first
    • spellingdate cast (2×)
    • determinismtie-breaker: no unique key in scope; rows that tie on all output columns are identical
    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • numericsdocs/NUMERICS.md: x / exchange rate cast to NUMERIC(18,6) (2×)
    • made explicita selected t.col gets AS col, its standard name made explicit (9×)
    • determinismthe standard leaves the place of NULLs in a sort to the implementation: NULLS LAST ascending, NULLS FIRST descending, as in the reference results (8×)
    • placeholderfetch first
    The benchmark text, against the submitted SQL
    WITH eligible_orders AS (    SELECT        o.id AS order_id,        o.tenant_id,        o.grand_total,        o.currency_code,        o.placed_at        o.tenant_id AS tenant_id,        o.grand_total AS grand_total,        o.currency_code AS currency_code,        o.placed_at AS placed_at    FROM orders o    WHERE o.placed_at >= DATE '2025-01-01'      AND o.placed_at < DATE '2026-01-01'      AND o.status <> 'cancelled'),order_revenue_eur AS (    SELECT        eo.tenant_id,        eo.order_id,        eo.grand_total / er.rate AS revenue_eur        eo.tenant_id AS tenant_id,        eo.order_id AS order_id,        CAST(eo.grand_total / er.rate AS NUMERIC(18,6)) AS revenue_eur    FROM eligible_orders eo    JOIN exchange_rates er      ON er.base_code = 'EUR'     AND er.quote_code = eo.currency_code     AND er.as_of = DATE(eo.placed_at)     AND er.as_of = CAST(eo.placed_at AS DATE)),tenant_order_totals AS (    SELECT        tenant_id,        SUM(revenue_eur) AS total_revenue_eur,        COUNT(DISTINCT order_id) AS order_count    FROM order_revenue_eur    GROUP BY tenant_id),discount_detail AS (    SELECT        od.tenant_id,        od.order_id,        od.amount / er.rate AS discount_eur,        COALESCE(od.coupon_id::varchar, od.code) AS discount_code_key        od.tenant_id AS tenant_id,        od.order_id AS order_id,        CAST(od.amount / er.rate AS NUMERIC(18,6)) AS discount_eur,        COALESCE(CAST(od.coupon_id AS varchar), od.code) AS discount_code_key    FROM order_discounts od    JOIN eligible_orders eo      ON eo.order_id = od.order_id     AND eo.tenant_id = od.tenant_id    JOIN exchange_rates er      ON er.base_code = 'EUR'     AND er.quote_code = od.currency_code     AND er.as_of = DATE(eo.placed_at)     AND er.as_of = CAST(eo.placed_at AS DATE)),tenant_discount_totals AS (    SELECT        tenant_id,        SUM(discount_eur) AS total_discount_eur,        COUNT(DISTINCT discount_code_key) AS distinct_discount_codes    FROM discount_detail    GROUP BY tenant_id),combined AS (    SELECT        t.name AS tenant_name,        t.industry AS vertical,        COALESCE(td.total_discount_eur, 0) AS discount_eur,        ot.total_revenue_eur AS revenue_eur,        ot.order_count,        ot.order_count AS order_count,        COALESCE(td.distinct_discount_codes, 0) AS distinct_discount_codes    FROM tenant_order_totals ot    JOIN tenants t ON t.id = ot.tenant_id    LEFT JOIN tenant_discount_totals td ON td.tenant_id = ot.tenant_id)SELECT    tenant_name,    vertical,    ROUND(discount_eur, 2) AS discount_amount_eur,    ROUND(revenue_eur, 2) AS order_revenue_eur,    ROUND(discount_eur / NULLIF(revenue_eur, 0) * 100, 2) AS discount_pct_of_revenue,    discount_eur AS discount_amount_eur,    revenue_eur AS order_revenue_eur,    discount_eur / NULLIF(revenue_eur, 0) * 100 AS discount_pct_of_revenue,    order_count,    distinct_discount_codes,    ROUND(discount_eur / NULLIF(SUM(discount_eur) OVER (), 0) * 100, 2) AS share_of_company_discount_pct    discount_eur / NULLIF(SUM(discount_eur) OVER (), 0) * 100 AS share_of_company_discount_pctFROM combinedORDER BY discount_amount_eur DESC, tenant_nameLIMIT 50ORDER BY discount_amount_eur DESC NULLS FIRST, tenant_name NULLS LAST, vertical NULLS LAST, order_revenue_eur NULLS LAST, discount_pct_of_revenue NULLS LAST, order_count NULLS LAST, distinct_discount_codes NULLS LAST, share_of_company_discount_pct NULLS LAST{{fetch_first(50)}}
    WITH eligible_orders AS (
        SELECT
            o.id AS order_id,
            o.tenant_id AS tenant_id,
            o.grand_total AS grand_total,
            o.currency_code AS currency_code,
            o.placed_at AS placed_at
        FROM orders o
        WHERE o.placed_at >= DATE '2025-01-01'
          AND o.placed_at < DATE '2026-01-01'
          AND o.status <> 'cancelled'
    ),
    order_revenue_eur AS (
        SELECT
            eo.tenant_id AS tenant_id,
            eo.order_id AS order_id,
            CAST(eo.grand_total / er.rate AS NUMERIC(18,6)) AS revenue_eur
        FROM eligible_orders eo
        JOIN exchange_rates er
          ON er.base_code = 'EUR'
         AND er.quote_code = eo.currency_code
         AND er.as_of = CAST(eo.placed_at AS DATE)
    ),
    tenant_order_totals AS (
        SELECT
            tenant_id,
            SUM(revenue_eur) AS total_revenue_eur,
            COUNT(DISTINCT order_id) AS order_count
        FROM order_revenue_eur
        GROUP BY tenant_id
    ),
    discount_detail AS (
        SELECT
            od.tenant_id AS tenant_id,
            od.order_id AS order_id,
            CAST(od.amount / er.rate AS NUMERIC(18,6)) AS discount_eur,
            COALESCE(CAST(od.coupon_id AS varchar), od.code) AS discount_code_key
        FROM order_discounts od
        JOIN eligible_orders eo
          ON eo.order_id = od.order_id
         AND eo.tenant_id = od.tenant_id
        JOIN exchange_rates er
          ON er.base_code = 'EUR'
         AND er.quote_code = od.currency_code
         AND er.as_of = CAST(eo.placed_at AS DATE)
    ),
    tenant_discount_totals AS (
        SELECT
            tenant_id,
            SUM(discount_eur) AS total_discount_eur,
            COUNT(DISTINCT discount_code_key) AS distinct_discount_codes
        FROM discount_detail
        GROUP BY tenant_id
    ),
    combined AS (
        SELECT
            t.name AS tenant_name,
            t.industry AS vertical,
            COALESCE(td.total_discount_eur, 0) AS discount_eur,
            ot.total_revenue_eur AS revenue_eur,
            ot.order_count AS order_count,
            COALESCE(td.distinct_discount_codes, 0) AS distinct_discount_codes
        FROM tenant_order_totals ot
        JOIN tenants t ON t.id = ot.tenant_id
        LEFT JOIN tenant_discount_totals td ON td.tenant_id = ot.tenant_id
    )
    SELECT
        tenant_name,
        vertical,
        discount_eur AS discount_amount_eur,
        revenue_eur AS order_revenue_eur,
        discount_eur / NULLIF(revenue_eur, 0) * 100 AS discount_pct_of_revenue,
        order_count,
        distinct_discount_codes,
        discount_eur / NULLIF(SUM(discount_eur) OVER (), 0) * 100 AS share_of_company_discount_pct
    FROM combined
    ORDER BY discount_amount_eur DESC NULLS FIRST, tenant_name NULLS LAST, vertical NULLS LAST, order_revenue_eur NULLS LAST, discount_pct_of_revenue NULLS LAST, order_count NULLS LAST, distinct_discount_codes NULLS LAST, share_of_company_discount_pct NULLS LAST
    FETCH FIRST 50 ROWS ONLY
    100 ms1 s10 sHyper279 msDuckDB3.20 sGizmoSQL2.25 sclickhouse_brew648 msFirebolterrorDataFusionerrorClickHouseerror
    • Firebolt{ "errors": [ { "description": "Line 17, Column 29: Operations between decimals with different precision and scale is not supported at the moment. Explicitly cast one of the decimals to other decimal precision and scale." } ], "query": { "query_id": "24bda8b4-5fa6-41a7-8f5a-7e7b18b44396", "query_lab
    • DataFusionArrow error: Invalid argument error: Invalid comparison operation: Decimal128(38, 6) == Decimal128(28, 6)
    • ClickHouseCode: 69. DB::Exception: Decimal result's scale is less than argument's one: while executing function divide on arguments __table4.grand_total Decimal(14, 4) Decimal64(size = 0), __table6.rate Decimal(12, 6) Decimal64(size = 0). (ARGUMENT_OUT_OF_BOUND)
  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

    Grace's whole session, 7 turns
    • The request, as Grace received it
      Report request from Oliver Grant (analyst for the Head of Pricing and Promotions):
      
      Title: Discount spend concentration by tenant and vertical, 2025
      Question: Are one or two merchants (or one vertical) responsible for most of our discount spend, relative to their share of revenue?
      Grain: one row per tenant
      Columns:
      - tenant name
      - vertical (tenants.industry)
      - total discount amount (EUR)
      - total order revenue, grand_total (EUR)
      - discount amount as % of order revenue
      - order count
      - distinct discount codes/coupons used
      - share of company-wide discount spend (%)
      Details: Source: order_discounts joined to orders (grand_total, currency_code, placed_at, status) and tenants (name, industry, default_currency_code). Filter orders.placed_at in 2025-01-01 to 2025-12-31, exclude cancelled orders. Convert all amounts to EUR via exchange_rates (base_code='EUR', quote_code=currency_code, as_of=placed_at date). 'Share of company-wide discount spend' = this tenant's EUR discount total / sum across all tenants. Order by total discount amount (EUR) descending. Note total tenant count returned; print top 50.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Grace calls dry_run
      WITH eligible_orders AS (
          SELECT
              o.id AS order_id,
              o.tenant_id,
              o.grand_total,
              o.currency_code,
              o.placed_at
          FROM orders o
          WHERE o.placed_at >= DATE '2025-01-01'
            AND o.placed_at < DATE '2026-01-01'
            AND o.status <> 'cancelled'
      ),
      order_revenue_eur AS (
          SELECT
              eo.tenant_id,
              eo.order_id,
              eo.grand_total / er.rate AS revenue_eur
          FROM eligible_orders eo
          JOIN exchange_rates er
            ON er.base_code = 'EUR'
           AND er.quote_code = eo.currency_code
           AND er.as_of = DATE(eo.placed_at)
      ),
      tenant_order_totals AS (
          SELECT
              tenant_id,
              SUM(revenue_eur) AS total_revenue_eur,
              COUNT(DISTINCT order_id) AS order_count
          FROM order_revenue_eur
          GROUP BY tenant_id
      ),
      discount_detail AS (
          SELECT
              od.tenant_id,
              od.order_id,
              od.amount / er.rate AS discount_eur,
              COALESCE(od.coupon_id::varchar, od.code) AS discount_code_key
          FROM order_discounts od
          JOIN eligible_orders eo
            ON eo.order_id = od.order_id
           AND eo.tenant_id = od.tenant_id
          JOIN exchange_rates er
            ON er.base_code = 'EUR'
           AND er.quote_code = od.currency_code
           AND er.as_of = DATE(eo.placed_at)
      ),
      tenant_discount_totals AS (
          SELECT
              tenant_id,
              SUM(discount_eur) AS total_discount_eur,
              COUNT(DISTINCT discount_code_key) AS distinct_discount_codes
          FROM discount_detail
          GROUP BY tenant_id
      ),
      combined AS (
          SELECT
              t.name AS tenant_name,
              t.industry AS vertical,
              COALESCE(td.total_discount_eur, 0) AS discount_eur,
              ot.total_revenue_eur AS revenue_eur,
              ot.order_count,
              COALESCE(td.distinct_discount_codes, 0) AS distinct_discount_codes
          FROM tenant_order_totals ot
          JOIN tenants t ON t.id = ot.tenant_id
          LEFT JOIN tenant_discount_totals td ON td.tenant_id = ot.tenant_id
      )
      SELECT
          tenant_name,
          vertical,
          ROUND(discount_eur, 2) AS discount_amount_eur,
          ROUND(revenue_eur, 2) AS order_revenue_eur,
          ROUND(discount_eur / NULLIF(revenue_eur, 0) * 100, 2) AS discount_pct_of_revenue,
          order_count,
          distinct_discount_codes,
          ROUND(discount_eur / NULLIF(SUM(discount_eur) OVER (), 0) * 100, 2) AS share_of_company_discount_pct
      FROM combined
      ORDER BY discount_amount_eur DESC, tenant_name
      LIMIT 50
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: tenant_name, vertical, discount_amount_eur, order_revenue_eur, discount_pct_of_revenue, order_count, distinct_discount_codes, share_of_company_discount_pct
    • GraceQuery compiles cleanly with the expected 8 columns. Submitting.
    • Grace calls submit
      WITH eligible_orders AS (
          SELECT
              o.id AS order_id,
              o.tenant_id,
              o.grand_total,
              o.currency_code,
              o.placed_at
          FROM orders o
          WHERE o.placed_at >= DATE '2025-01-01'
            AND o.placed_at < DATE '2026-01-01'
            AND o.status <> 'cancelled'
      ),
      order_revenue_eur AS (
          SELECT
              eo.tenant_id,
              eo.order_id,
              eo.grand_total / er.rate AS revenue_eur
          FROM eligible_orders eo
          JOIN exchange_rates er
            ON er.base_code = 'EUR'
           AND er.quote_code = eo.currency_code
           AND er.as_of = DATE(eo.placed_at)
      ),
      tenant_order_totals AS (
          SELECT
              tenant_id,
              SUM(revenue_eur) AS total_revenue_eur,
              COUNT(DISTINCT order_id) AS order_count
          FROM order_revenue_eur
          GROUP BY tenant_id
      ),
      discount_detail AS (
          SELECT
              od.tenant_id,
              od.order_id,
              od.amount / er.rate AS discount_eur,
              COALESCE(od.coupon_id::varchar, od.code) AS discount_code_key
          FROM order_discounts od
          JOIN eligible_orders eo
            ON eo.order_id = od.order_id
           AND eo.tenant_id = od.tenant_id
          JOIN exchange_rates er
            ON er.base_code = 'EUR'
           AND er.quote_code = od.currency_code
           AND er.as_of = DATE(eo.placed_at)
      ),
      tenant_discount_totals AS (
          SELECT
              tenant_id,
              SUM(discount_eur) AS total_discount_eur,
              COUNT(DISTINCT discount_code_key) AS distinct_discount_codes
          FROM discount_detail
          GROUP BY tenant_id
      ),
      combined AS (
          SELECT
              t.name AS tenant_name,
              t.industry AS vertical,
              COALESCE(td.total_discount_eur, 0) AS discount_eur,
              ot.total_revenue_eur AS revenue_eur,
              ot.order_count,
              COALESCE(td.distinct_discount_codes, 0) AS distinct_discount_codes
          FROM tenant_order_totals ot
          JOIN tenants t ON t.id = ot.tenant_id
          LEFT JOIN tenant_discount_totals td ON td.tenant_id = ot.tenant_id
      )
      SELECT
          tenant_name,
          vertical,
          ROUND(discount_eur, 2) AS discount_amount_eur,
          ROUND(revenue_eur, 2) AS order_revenue_eur,
          ROUND(discount_eur / NULLIF(revenue_eur, 0) * 100, 2) AS discount_pct_of_revenue,
          order_count,
          distinct_discount_codes,
          ROUND(discount_eur / NULLIF(SUM(discount_eur) OVER (), 0) * 100, 2) AS share_of_company_discount_pct
      FROM combined
      ORDER BY discount_amount_eur DESC, tenant_name
      LIMIT 50
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • GraceSubmitted. Summary of the approach: - **Base population**: all non-cancelled orders with `placed_at` in 2025, per tenant. - **Revenue**: `grand_total` converted to EUR day-by-day via `exchange_rates` (EUR→local rate, so divide to get EUR). - **Discounts**: `order_discounts.amount` converted to EUR the same way, joined only to orders in the 2025 eligible set. - **Distinct codes**: counts distinct `coupon_id` (falling back to the free-text `code` when no coupon is linked). - **Share of company spend**: each tenant's EUR discount total divided by the window sum across all tenants. - Tenants with no discounts still appear (discount = 0, share = 0) so the "concentration" picture is complete; sorted by discount EUR descending, top 50 printed, as requested.