DB Olympics

Queries · q373 · Head of Lifecycle Marketing · week 2, night 2

Refund rate on orders with a same-day points redemption

“Using date-proximity matching instead of the unusable order_id link, do loyalty members' orders that coincide with a points redemption on the same calendar day show a different refund rate than their other orders?”

Manager · asked the questionAisha RahmanHead of Lifecycle Marketing. Ran customer messaging at a subscription box company.
Analyst · planned the reportIngrid SolbergRisk-focused: looks for the tail, the outliers and the worst cases.
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 Lifecycle Marketing's desk

    Week 1; shared with Tobias Lindqvist, Chief Financial Officer

    Is the loyalty and referral programme worth it? Do members and referred customers behave differently from others, and what does the programme cost?

  2. Aisha Rahman writes to Ingrid Solberg

    The manager, at the start of week 2

    Subject: Re: Loyalty & referral — thank you, and where to dig next

    Ingrid, this is excellent — especially catching that the refund-rate gap was a vertical mix artifact. Good instinct to go back and break that out rather than let the scary headline stand.

    What surprised me most, and what I want explained before we take this to Tobias as a joint recommendation: a 19.4% cost-to-member-revenue ratio is strikingly high, and members showing lower revenue and order counts than non-members is the opposite of what a loyalty programme is supposed to produce. I don't want to present "the programme loses money" to leadership until I understand whether that's a true causal effect or another mix artifact like the refund rate turned out to be — since 72% of members sit in one vertical, I'm wary of a second apples-to-oranges comparison hiding in there.

    Questions for this week, in my own words:

    1. Within Apparel alone — since that's where almost all members live — do members still look worse off than similar non-member customers in that same vertical, once we also account for how long they've been customers? That's the comparison I actually trust as a verdict on the programme.
    2. Is the growing points liability a timing issue or a real design flaw? I want to understand whether we're simply in a "young programme, redemptions lag issuance" phase that will level out, or whether the redemption rate structurally understates true future cost — i.e., should I expect that €491k to keep climbing indefinitely at this pace.
    3. Can we fix the redemption-to-order linkage well enough to test the gaming hypothesis properly? That was left untested, not cleared, and it's exactly the kind of finding that would change my recommendation, so I'd like one more serious attempt before we call it inconclusive for good.
    4. If the member economics do hold up as genuinely negative, is there a design change that would plausibly fix it — rather than only "keep, cut, or extend to B2B" as the choice — are there any patterns in how the better-performing members (if any exist) use the programme differently from the rest? I don't need a redesign from you, just whether the data shows any sign of what a healthier version would look like.

    The B2B extension question can wait — I agree we shouldn't open that door until we trust the member economics number. Let's keep that out of this week's slots unless there's room left over.

    Thanks again, Ingrid — this is exactly the kind of rigor I want from this team.

    Best, Aisha

  3. Ingrid Solberg plans the night

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

    Night 1 answered Aisha's Q1 cleanly: within Apparel and controlling for tenure, order counts and refund rates between members and non-members are essentially indistinguishable in every tenure band (refund rates all cluster 33-40% regardless of segment) - the refund-rate and order-frequency 'penalty' really was mostly mix artifact. But a new, robust finding emerged: average order value is 28-40% lower for members than non-members in every single tenure band within Apparel - consistent and large, so that's the real driver of lower member revenue, and it needs explaining before I call it a verdict. Report 2 answered Q2 well: redemption rate rises steadily with cohort age (4% for 2-month-old cohorts up to ~32-37% for cohorts over 2 years old) and then plateaus around that 32-37% level even for the oldest 2023 cohorts - so it's both a timing lag (explains why young cohorts drag the blended rate down) and a structural ceiling (most points, even given 3 years, never get redeemed) - meaning the liability will keep growing in euros as we add members, while each cohort's own eventual redemption converges to roughly a third of what's issued. Report 3 gave a clean, important negative result for Q3: order_id is populated on 100% of 'earn' transactions but 0% of 343 'burn' transactions - the data model genuinely never records which order (if any) a redemption applied to, so the order_id-based gaming test was never going to work; I need a different join (same-user, same-day proximity) before I can call this inconclusive for good. Tonight: (1) retry the gaming test using date-proximity matching instead of order_id; (2) decompose the Apparel AOV gap into subtotal vs discount to see if heavier discounting (consistent with points use) explains it; (3) start on Q4 by comparing top-revenue members against the rest of the member base to see if better performers use the programme differently.

    Refund rate on orders with a same-day points redemption
    Question
    Using date-proximity matching instead of the unusable order_id link, do loyalty members' orders that coincide with a points redemption on the same calendar day show a different refund rate than their other orders?
    One row per
    order type among loyalty members' orders: 'same-day points redemption' vs 'no same-day points redemption'
    Columns
    • order_type
    • order_count
    • distinct_customers
    • refund_rate_pct
    • avg_order_value_eur
    • avg_points_redeemed_that_day
  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 loyalty_user_ids AS (
      SELECT DISTINCT user_id FROM loyalty_accounts
    ),
    eligible_orders AS (
      SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status
      FROM orders o
      JOIN loyalty_user_ids lu ON lu.user_id = o.user_id
      WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01'
    ),
    burn_by_user_day AS (
      SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points
      FROM loyalty_transactions
      WHERE direction = 'burn'
      GROUP BY user_id, CAST(occurred_at AS DATE)
    ),
    classified_orders AS (
      SELECT
        eo.order_id,
        eo.user_id,
        eo.placed_at,
        eo.grand_total,
        eo.currency_code,
        eo.status,
        bd.day_points,
        CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type
      FROM eligible_orders eo
      LEFT JOIN burn_by_user_day bd
        ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE)
    ),
    refund_flags AS (
      SELECT
        co.order_id,
        co.order_type,
        CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0)
          OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id)
        THEN 1 ELSE 0 END AS is_refunded
      FROM classified_orders co
    ),
    order_value_eur AS (
      SELECT
        co.order_id,
        co.order_type,
        CASE WHEN co.currency_code = 'EUR' THEN co.grand_total
             ELSE co.grand_total / er.rate END AS grand_total_eur
      FROM classified_orders co
      LEFT JOIN exchange_rates er
        ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE)
      WHERE co.status <> 'cancelled'
    ),
    order_counts AS (
      SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day
      FROM classified_orders
      GROUP BY order_type
    ),
    refund_rates AS (
      SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct
      FROM refund_flags
      GROUP BY order_type
    ),
    avg_values AS (
      SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur
      FROM order_value_eur
      GROUP BY order_type
    )
    SELECT
      oc.order_type,
      oc.order_count,
      oc.distinct_customers,
      ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct,
      ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur,
      ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day
    FROM order_counts oc
    JOIN refund_rates rr ON rr.order_type = oc.order_type
    JOIN avg_values av ON av.order_type = oc.order_type
    ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_type

    “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. Summary of approach: - Population: orders from users with a loyalty_accounts row, placed_at in 2023‑01‑01–2025‑12‑31. - Classification: an order is 'same-day points redemption' if the same user_id has any loyalty_transactions row with direction='burn' on the same calendar date as placed_at (date-proximity match, as requested instead of the broken order_id link). - refund_rate_pct: share of orders (all statuses) with payments.amount_refunded > 0 or a linked order_returns row. - avg_order_value_eur: average grand_total of non-cancelled orders, converted to EUR using exchange_rates (EUR→currency rate as of the order date). - avg_points_redeemed_that_day: average of the summed absolute burn points for that user/day (0 for the no-redemption group). Noted in the submit note that points are summed across multiple same-day burns per user before averaging, and that order_count/refund_rate include all order statuses while avg_order_value_eur excludes cancelled orders, per the stated definitions.”

  5. The report comes back overnight

    As Ingrid Solberg saw it, from the small dataset the agents worked on

    order_type                    | order_count | distinct_customers | refund_rate_pct | avg_order_value_eur | avg_points_redeemed_that_day
    ------------------------------+-------------+--------------------+-----------------+---------------------+-----------------------------
    same-day points redemption    |           5 |                  5 |            40.0 |              183.69 |                        500.0
    no same-day points redemption |        4936 |               1330 |           32.35 |              194.41 |                          0.0
    (2 rows)
  6. What came of it

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

    It builds on:

  7. It becomes benchmark query q373

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

    • numericsdocs/NUMERICS.md: AVG over an integer computed as a decimal: AVG(CAST(x AS NUMERIC(18,6)))
    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • numericsdocs/NUMERICS.md: x / exchange rate cast to NUMERIC(18,6)
    • made explicita selected t.col gets AS col, its standard name made explicit (20×)
    • 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 loyalty_user_ids AS (  SELECT DISTINCT user_id FROM loyalty_accounts),eligible_orders AS (  SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status  SELECT o.id AS order_id, o.tenant_id AS tenant_id, o.user_id AS user_id, o.placed_at AS placed_at, o.grand_total AS grand_total, o.currency_code AS currency_code, o.status AS status  FROM orders o  JOIN loyalty_user_ids lu ON lu.user_id = o.user_id  WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01'),burn_by_user_day AS (  SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points  FROM loyalty_transactions  WHERE direction = 'burn'  GROUP BY user_id, CAST(occurred_at AS DATE)),classified_orders AS (  SELECT    eo.order_id,    eo.user_id,    eo.placed_at,    eo.grand_total,    eo.currency_code,    eo.status,    bd.day_points,    eo.order_id AS order_id,    eo.user_id AS user_id,    eo.placed_at AS placed_at,    eo.grand_total AS grand_total,    eo.currency_code AS currency_code,    eo.status AS status,    bd.day_points AS day_points,    CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type  FROM eligible_orders eo  LEFT JOIN burn_by_user_day bd    ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE)),refund_flags AS (  SELECT    co.order_id,    co.order_type,    co.order_id AS order_id,    co.order_type AS order_type,    CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0)      OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id)    THEN 1 ELSE 0 END AS is_refunded  FROM classified_orders co),order_value_eur AS (  SELECT    co.order_id,    co.order_type,    co.order_id AS order_id,    co.order_type AS order_type,    CASE WHEN co.currency_code = 'EUR' THEN co.grand_total         ELSE co.grand_total / er.rate END AS grand_total_eur         ELSE CAST(co.grand_total / er.rate AS NUMERIC(18,6)) END AS grand_total_eur  FROM classified_orders co  LEFT JOIN exchange_rates er    ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE)  WHERE co.status <> 'cancelled'),order_counts AS (  SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day  FROM classified_orders  GROUP BY order_type),refund_rates AS (  SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct  SELECT order_type, AVG(CAST(is_refunded AS NUMERIC(18,6))) * 100 AS refund_rate_pct  FROM refund_flags  GROUP BY order_type),avg_values AS (  SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur  FROM order_value_eur  GROUP BY order_type)SELECT  oc.order_type,  oc.order_count,  oc.distinct_customers,  ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct,  ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur,  ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day  oc.order_type AS order_type,  oc.order_count AS order_count,  oc.distinct_customers AS distinct_customers,  rr.refund_rate_pct AS refund_rate_pct,  av.avg_order_value_eur AS avg_order_value_eur,  oc.avg_points_redeemed_that_day AS avg_points_redeemed_that_dayFROM order_counts ocJOIN refund_rates rr ON rr.order_type = oc.order_typeJOIN avg_values av ON av.order_type = oc.order_typeORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_typeORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END NULLS LAST, oc.order_type NULLS LAST
    WITH loyalty_user_ids AS (
      SELECT DISTINCT user_id FROM loyalty_accounts
    ),
    eligible_orders AS (
      SELECT o.id AS order_id, o.tenant_id AS tenant_id, o.user_id AS user_id, o.placed_at AS placed_at, o.grand_total AS grand_total, o.currency_code AS currency_code, o.status AS status
      FROM orders o
      JOIN loyalty_user_ids lu ON lu.user_id = o.user_id
      WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01'
    ),
    burn_by_user_day AS (
      SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points
      FROM loyalty_transactions
      WHERE direction = 'burn'
      GROUP BY user_id, CAST(occurred_at AS DATE)
    ),
    classified_orders AS (
      SELECT
        eo.order_id AS order_id,
        eo.user_id AS user_id,
        eo.placed_at AS placed_at,
        eo.grand_total AS grand_total,
        eo.currency_code AS currency_code,
        eo.status AS status,
        bd.day_points AS day_points,
        CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type
      FROM eligible_orders eo
      LEFT JOIN burn_by_user_day bd
        ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE)
    ),
    refund_flags AS (
      SELECT
        co.order_id AS order_id,
        co.order_type AS order_type,
        CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0)
          OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id)
        THEN 1 ELSE 0 END AS is_refunded
      FROM classified_orders co
    ),
    order_value_eur AS (
      SELECT
        co.order_id AS order_id,
        co.order_type AS order_type,
        CASE WHEN co.currency_code = 'EUR' THEN co.grand_total
             ELSE CAST(co.grand_total / er.rate AS NUMERIC(18,6)) END AS grand_total_eur
      FROM classified_orders co
      LEFT JOIN exchange_rates er
        ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE)
      WHERE co.status <> 'cancelled'
    ),
    order_counts AS (
      SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day
      FROM classified_orders
      GROUP BY order_type
    ),
    refund_rates AS (
      SELECT order_type, AVG(CAST(is_refunded AS NUMERIC(18,6))) * 100 AS refund_rate_pct
      FROM refund_flags
      GROUP BY order_type
    ),
    avg_values AS (
      SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur
      FROM order_value_eur
      GROUP BY order_type
    )
    SELECT
      oc.order_type AS order_type,
      oc.order_count AS order_count,
      oc.distinct_customers AS distinct_customers,
      rr.refund_rate_pct AS refund_rate_pct,
      av.avg_order_value_eur AS avg_order_value_eur,
      oc.avg_points_redeemed_that_day AS avg_points_redeemed_that_day
    FROM order_counts oc
    JOIN refund_rates rr ON rr.order_type = oc.order_type
    JOIN avg_values av ON av.order_type = oc.order_type
    ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END NULLS LAST, oc.order_type NULLS LAST
    100 ms1 s10 sHyper154 msDuckDB216 msGizmoSQL217 msclickhouse_brew1.39 sFirebolterrorDataFusionerrorClickHouseerror
    • Firebolt{ "errors": [ { "description": "Line 44, Column 35: 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": "3dc2115b-aa38-4f82-b741-d5b1c9efb292", "query_lab
    • DataFusionThis feature is not implemented: Physical plan does not support logical expression Exists(Exists { subquery: <subquery>, negated: false })
    • ClickHouseCode: 69. DB::Exception: Decimal result's scale is less than argument's one: while executing function divide on arguments __table26.grand_total Decimal(14, 4) Decimal64(size = 0), __table33.rate Nullable(Decimal(12, 6)) Nullable(size = 0, Decimal64(size = 0), UInt8(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 Ingrid Solberg (analyst for the Head of Lifecycle Marketing):
      
      Title: Refund rate on orders with a same-day points redemption
      Question: Using date-proximity matching instead of the unusable order_id link, do loyalty members' orders that coincide with a points redemption on the same calendar day show a different refund rate than their other orders?
      Grain: one row per order type among loyalty members' orders: 'same-day points redemption' vs 'no same-day points redemption'
      Columns:
      - order_type
      - order_count
      - distinct_customers
      - refund_rate_pct
      - avg_order_value_eur
      - avg_points_redeemed_that_day
      Details: Population: all orders (any status, placed_at between 2023-01-01 and 2025-12-31) placed by users who have a loyalty_accounts row. For each such order, classify as 'same-day points redemption' if there exists a loyalty_transactions row for the same user_id with direction = 'burn' whose occurred_at falls on the same calendar date as the order's placed_at; otherwise 'no same-day points redemption'. refund_rate_pct = share of orders in the group with payments.amount_refunded greater than 0 OR an order_returns row, same definition used throughout. avg_order_value_eur = average grand_total of non-cancelled orders in the group, converted to EUR via exchange_rates (as_of placed_at). avg_points_redeemed_that_day = average absolute points value of the matching same-day burn transaction(s) for the 'same-day' group (0 for the other group). Order rows: 'same-day points redemption' first.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Grace calls dry_run
      WITH loyalty_user_ids AS (
        SELECT DISTINCT user_id FROM loyalty_accounts
      ),
      eligible_orders AS (
        SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status
        FROM orders o
        JOIN loyalty_user_ids lu ON lu.user_id = o.user_id
        WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01'
      ),
      burn_by_user_day AS (
        SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points
        FROM loyalty_transactions
        WHERE direction = 'burn'
        GROUP BY user_id, CAST(occurred_at AS DATE)
      ),
      classified_orders AS (
        SELECT
          eo.order_id,
          eo.user_id,
          eo.placed_at,
          eo.grand_total,
          eo.currency_code,
          eo.status,
          bd.day_points,
          CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type
        FROM eligible_orders eo
        LEFT JOIN burn_by_user_day bd
          ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE)
      ),
      refund_flags AS (
        SELECT
          co.order_id,
          co.order_type,
          CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0)
            OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id)
          THEN 1 ELSE 0 END AS is_refunded
        FROM classified_orders co
      ),
      order_value_eur AS (
        SELECT
          co.order_id,
          co.order_type,
          CASE WHEN co.currency_code = 'EUR' THEN co.grand_total
               ELSE co.grand_total / er.rate END AS grand_total_eur
        FROM classified_orders co
        LEFT JOIN exchange_rates er
          ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE)
        WHERE co.status <> 'cancelled'
      ),
      order_counts AS (
        SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day
        FROM classified_orders
        GROUP BY order_type
      ),
      refund_rates AS (
        SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct
        FROM refund_flags
        GROUP BY order_type
      ),
      avg_values AS (
        SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur
        FROM order_value_eur
        GROUP BY order_type
      )
      SELECT
        oc.order_type,
        oc.order_count,
        oc.distinct_customers,
        ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct,
        ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur,
        ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day
      FROM order_counts oc
      JOIN refund_rates rr ON rr.order_type = oc.order_type
      JOIN avg_values av ON av.order_type = oc.order_type
      ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_type
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: order_type, order_count, distinct_customers, refund_rate_pct, avg_order_value_eur, avg_points_redeemed_that_day
    • GraceQuery compiles and returns the expected columns. Submitting.
    • Grace calls submit
      WITH loyalty_user_ids AS (
        SELECT DISTINCT user_id FROM loyalty_accounts
      ),
      eligible_orders AS (
        SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status
        FROM orders o
        JOIN loyalty_user_ids lu ON lu.user_id = o.user_id
        WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01'
      ),
      burn_by_user_day AS (
        SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points
        FROM loyalty_transactions
        WHERE direction = 'burn'
        GROUP BY user_id, CAST(occurred_at AS DATE)
      ),
      classified_orders AS (
        SELECT
          eo.order_id,
          eo.user_id,
          eo.placed_at,
          eo.grand_total,
          eo.currency_code,
          eo.status,
          bd.day_points,
          CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type
        FROM eligible_orders eo
        LEFT JOIN burn_by_user_day bd
          ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE)
      ),
      refund_flags AS (
        SELECT
          co.order_id,
          co.order_type,
          CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0)
            OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id)
          THEN 1 ELSE 0 END AS is_refunded
        FROM classified_orders co
      ),
      order_value_eur AS (
        SELECT
          co.order_id,
          co.order_type,
          CASE WHEN co.currency_code = 'EUR' THEN co.grand_total
               ELSE co.grand_total / er.rate END AS grand_total_eur
        FROM classified_orders co
        LEFT JOIN exchange_rates er
          ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE)
        WHERE co.status <> 'cancelled'
      ),
      order_counts AS (
        SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day
        FROM classified_orders
        GROUP BY order_type
      ),
      refund_rates AS (
        SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct
        FROM refund_flags
        GROUP BY order_type
      ),
      avg_values AS (
        SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur
        FROM order_value_eur
        GROUP BY order_type
      )
      SELECT
        oc.order_type,
        oc.order_count,
        oc.distinct_customers,
        ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct,
        ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur,
        ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day
      FROM order_counts oc
      JOIN refund_rates rr ON rr.order_type = oc.order_type
      JOIN avg_values av ON av.order_type = oc.order_type
      ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_type
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • GraceSubmitted. Summary of approach: - **Population**: orders from users with a `loyalty_accounts` row, `placed_at` in 2023‑01‑01–2025‑12‑31. - **Classification**: an order is `'same-day points redemption'` if the same `user_id` has any `loyalty_transactions` row with `direction='burn'` on the same calendar date as `placed_at` (date-proximity match, as requested instead of the broken order_id link). - **refund_rate_pct**: share of orders (all statuses) with `payments.amount_refunded > 0` or a linked `order_returns` row. - **avg_order_value_eur**: average `grand_total` of non-cancelled orders, converted to EUR using `exchange_rates` (EUR→currency rate as of the order date). - **avg_points_redeemed_that_day**: average of the summed absolute burn points for that user/day (0 for the no-redemption group). Noted in the submit note that points are summed across multiple same-day burns per user before averaging, and that order_count/refund_rate include all order statuses while avg_order_value_eur excludes cancelled orders, per the stated definitions.