DB Olympics

Queries · q142 · Head of Merchandising · week 1, night 3

Home & Living December 2025 Rating Dip: Merchant Breakdown

“Within Home & Living, is the December 2025 rating decline concentrated in a few merchants or spread across the vertical?”

Manager · asked the questionFreya LindgrenHead of Merchandising. Came from a fashion marketplace's catalog team. Responsible for helping merchants present their products well.
Analyst · planned the reportZara AhmedExploratory: looks at the raw detail of an unfamiliar area before aggregating it.
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. Freya Lindgren writes to Zara Ahmed

    The manager, at the start of week 1

    Subject: My first-week priorities — catalog questions

    Hi Zara,

    Great to have you helping me get oriented this week. I know slots are tight, so here's what I most want to understand first. Pick the ones you think will give us the clearest picture given the report budget — happy to defer the rest to next week.

    1. How healthy is our catalog overall, and where is it thin? I'd like a sense of how many products and variants each merchant is actually running, which ones feel well-built out (good imagery, descriptions, variants) versus sparse, and whether that varies a lot across merchants or verticals. I need this to know where to focus my attention first.
    2. Does catalog quality actually move sales? I'm curious whether products with richer content — more images, more reviews, better ratings — sell noticeably better than ones without. I want to build the case (to myself and to merchants) for why investing in catalog presentation is worth it.
    3. What do customers think of the products, and where are the trouble spots? I'd like to see how reviews and ratings are trending, which products or categories are getting poor feedback, and whether there are products with surprisingly few or no reviews despite decent sales. This tells me where to nudge merchants on quality or listing improvements.
    4. Are we using collections and bundles well? I want to know how much merchants are leaning on curated collections and bundles versus just flat product listings, and whether those grouped presentations correlate with better performance. This will shape whether I push merchandising tools harder in my conversations with merchants.
    5. How are our top merchants' catalogs structured compared to the long tail? Since a handful of merchants drive most of the volume, I'd like to understand if their catalogs look meaningfully different (size, categorization, media richness) from smaller merchants — it'll help me figure out what "good" looks like and what advice to bring to the smaller ones.

    Let me know what's realistic to cover by Friday, and flag if any of these need to be split into smaller questions on your end.

    Thanks, Freya

  2. Zara Ahmed plans the night

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

    Night 2 takeaways: (1) Even within Apparel & Footwear alone, the richness story is not a clean monotonic 'more images = more sales' curve — the big jump is between 0 images (109 EUR/product, and these products also have far fewer variants, ~4 vs ~13, suggesting they're incomplete/new listings) and 1+ images (355-399 EUR/product); beyond that, 2-3/4-6/7+ bounce around without a clear ladder. So the honest message for Freya is 'baseline completeness matters a lot, marginal richness less so' rather than 'more is always better'. (2) Reviews-per-100-orders is noisy but flat (~10-20%) across the whole 3-year window with no trend — so the rising raw review counts are explained by rising order volume, not growing review engagement; December 2025's high avg_rating=3.71 dip is a ratings-quality story, not a volume-of-reviews story (its reviews-per-100-orders, 15.16, is unremarkable). (3) The vertical breakdown shows Home & Living had the sharpest, most volume-credible decline (3.86→3.36, n=42→59, 35.6% 1-2 star), while Apparel & Footwear's decline is milder (-0.11) but carries about half of all December reviews (219 of ~454), so it matters in absolute terms too. Tonight I want to localize the Home & Living dip to specific merchants (one bad actor vs widespread), get a concrete worst-rated-products list platform-wide to ground Q3's 'trouble spots' ask, and open up Q4 (collections/bundles adoption vs performance), which I haven't touched yet. I'm holding the few-reviews-despite-good-sales angle and the dedicated top-vs-long-tail structural comparison (Q5) for night 4, since night 3's findings may reshape what's worth asking there.

    Home & Living December 2025 Rating Dip: Merchant Breakdown
    Question
    Within Home & Living, is the December 2025 rating decline concentrated in a few merchants or spread across the vertical?
    One row per
    merchant (tenant) in the Home & Living industry
    Columns
    • merchant_name
    • dec2025_review_count
    • dec2025_avg_rating
    • dec2025_pct_1_2_star
    • jan_to_nov_2025_avg_rating
    • rating_change_pts
  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,
           d.review_count AS dec2025_review_count,
           d.avg_rating AS dec2025_avg_rating,
           d.pct_1_2_star AS dec2025_pct_1_2_star,
           j.avg_rating AS jan_to_nov_2025_avg_rating,
           ROUND(d.avg_rating - j.avg_rating, 2) AS rating_change_pts
    FROM tenants t
    JOIN (
      SELECT p.tenant_id,
             COUNT(*) AS review_count,
             ROUND(AVG(pr.rating), 2) AS avg_rating,
             ROUND(100.0 * SUM(CASE WHEN pr.rating <= 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1_2_star
      FROM product_reviews pr
      JOIN products p ON pr.product_id = p.id
      WHERE pr.is_approved = true
        AND pr.created_at >= DATE '2025-12-01'
        AND pr.created_at < DATE '2026-01-01'
      GROUP BY p.tenant_id
    ) d ON d.tenant_id = t.id
    JOIN (
      SELECT p.tenant_id,
             ROUND(AVG(pr.rating), 2) AS avg_rating
      FROM product_reviews pr
      JOIN products p ON pr.product_id = p.id
      WHERE pr.is_approved = true
        AND pr.created_at >= DATE '2025-01-01'
        AND pr.created_at < DATE '2025-12-01'
      GROUP BY p.tenant_id
    ) j ON j.tenant_id = t.id
    WHERE t.industry = 'Home & Living'
    ORDER BY rating_change_pts ASC, d.review_count DESC

    “Query compiles correctly. Submitting now.”

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

    “Submitted. The report joins product_reviews → products → tenants, scoped to approved reviews in the Home & Living industry, with separate December 2025 and January–November 2025 aggregates per merchant, ordered by biggest rating decline first.”

  4. The report comes back overnight

    As Zara Ahmed saw it, from the small dataset the agents worked on

    merchant_name       | dec2025_review_count | dec2025_avg_rating | dec2025_pct_1_2_star | jan_to_nov_2025_avg_rating | rating_change_pts
    --------------------+----------------------+--------------------+----------------------+----------------------------+------------------
    Willow & Wren       |                    4 |                1.5 |                 75.0 |                       3.54 |             -2.04
    Haven Linen         |                    1 |                2.0 |                100.0 |                        4.0 |              -2.0
    Wohnglück           |                    3 |                3.0 |                 33.3 |                       4.57 |             -1.57
    Fern & Fable        |                    1 |                3.0 |                  0.0 |                       4.14 |             -1.14
    Driftwood Home      |                    1 |                2.0 |                100.0 |                        3.0 |              -1.0
    Fennel & Flint      |                   14 |               3.14 |                 35.7 |                       4.11 |             -0.97
    Coastline Interiors |                    6 |               3.67 |                 33.3 |                       4.29 |             -0.62
    Wiesgrund Wohnen    |                   12 |                3.5 |                 41.7 |                        4.1 |              -0.6
    Hus & Hem           |                    1 |                3.0 |                  0.0 |                        3.4 |              -0.4
    Linden & Loom       |                    8 |               3.88 |                 25.0 |                       4.18 |              -0.3
    Lamplight Living    |                    1 |                4.0 |                  0.0 |                        4.2 |              -0.2
    Kettle & Key        |                    3 |               3.67 |                 33.3 |                       3.67 |               0.0
    Tiny Atelier        |                    1 |                5.0 |                  0.0 |                       4.25 |              0.75
    (13 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 q142

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

    • determinismtie-breaker: one row per tenant
    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision
    • numericsdocs/NUMERICS.md: rounding removed; results keep full precision; AVG over an integer computed as a decimal: AVG(CAST(x AS NUMERIC(18,6)))
    • 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 (2×)
    • determinismthe standard leaves the place of NULLs in a sort to the implementation: NULLS LAST ascending, NULLS FIRST descending, as in the reference results (3×)
    The benchmark text, against the submitted SQL
    SELECT t.name AS merchant_name,       d.review_count AS dec2025_review_count,       d.avg_rating AS dec2025_avg_rating,       d.pct_1_2_star AS dec2025_pct_1_2_star,       j.avg_rating AS jan_to_nov_2025_avg_rating,       ROUND(d.avg_rating - j.avg_rating, 2) AS rating_change_pts       d.avg_rating - j.avg_rating AS rating_change_ptsFROM tenants tJOIN (  SELECT p.tenant_id,  SELECT p.tenant_id AS tenant_id,         COUNT(*) AS review_count,         ROUND(AVG(pr.rating), 2) AS avg_rating,         ROUND(100.0 * SUM(CASE WHEN pr.rating <= 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1_2_star         AVG(CAST(pr.rating AS NUMERIC(18,6))) AS avg_rating,         100.0 * SUM(CASE WHEN pr.rating <= 2 THEN 1 ELSE 0 END) / COUNT(*) AS pct_1_2_star  FROM product_reviews pr  JOIN products p ON pr.product_id = p.id  WHERE pr.is_approved = true    AND pr.created_at >= DATE '2025-12-01'    AND pr.created_at < DATE '2026-01-01'  GROUP BY p.tenant_id) d ON d.tenant_id = t.idJOIN (  SELECT p.tenant_id,         ROUND(AVG(pr.rating), 2) AS avg_rating  SELECT p.tenant_id AS tenant_id,         AVG(CAST(pr.rating AS NUMERIC(18,6))) AS avg_rating  FROM product_reviews pr  JOIN products p ON pr.product_id = p.id  WHERE pr.is_approved = true    AND pr.created_at >= DATE '2025-01-01'    AND pr.created_at < DATE '2025-12-01'  GROUP BY p.tenant_id) j ON j.tenant_id = t.idWHERE t.industry = 'Home & Living'ORDER BY rating_change_pts ASC, d.review_count DESCORDER BY rating_change_pts ASC NULLS LAST, d.review_count DESC NULLS FIRST, t.id ASC NULLS LAST
    SELECT t.name AS merchant_name,
           d.review_count AS dec2025_review_count,
           d.avg_rating AS dec2025_avg_rating,
           d.pct_1_2_star AS dec2025_pct_1_2_star,
           j.avg_rating AS jan_to_nov_2025_avg_rating,
           d.avg_rating - j.avg_rating AS rating_change_pts
    FROM tenants t
    JOIN (
      SELECT p.tenant_id AS tenant_id,
             COUNT(*) AS review_count,
             AVG(CAST(pr.rating AS NUMERIC(18,6))) AS avg_rating,
             100.0 * SUM(CASE WHEN pr.rating <= 2 THEN 1 ELSE 0 END) / COUNT(*) AS pct_1_2_star
      FROM product_reviews pr
      JOIN products p ON pr.product_id = p.id
      WHERE pr.is_approved = true
        AND pr.created_at >= DATE '2025-12-01'
        AND pr.created_at < DATE '2026-01-01'
      GROUP BY p.tenant_id
    ) d ON d.tenant_id = t.id
    JOIN (
      SELECT p.tenant_id AS tenant_id,
             AVG(CAST(pr.rating AS NUMERIC(18,6))) AS avg_rating
      FROM product_reviews pr
      JOIN products p ON pr.product_id = p.id
      WHERE pr.is_approved = true
        AND pr.created_at >= DATE '2025-01-01'
        AND pr.created_at < DATE '2025-12-01'
      GROUP BY p.tenant_id
    ) j ON j.tenant_id = t.id
    WHERE t.industry = 'Home & Living'
    ORDER BY rating_change_pts ASC NULLS LAST, d.review_count DESC NULLS FIRST, t.id ASC NULLS LAST
    10 ms100 ms1 sHyper11.3 msDuckDB12.8 msGizmoSQL29.9 msclickhouse_brew88.8 msFirebolt55.8 msDataFusion137 msClickHouse103 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

    Felix's whole session, 7 turns
    • The request, as Felix received it
      Report request from Zara Ahmed (analyst for the Head of Merchandising):
      
      Title: Home & Living December 2025 Rating Dip: Merchant Breakdown
      Question: Within Home & Living, is the December 2025 rating decline concentrated in a few merchants or spread across the vertical?
      Grain: one row per merchant (tenant) in the Home & Living industry
      Columns:
      - merchant_name
      - dec2025_review_count
      - dec2025_avg_rating
      - dec2025_pct_1_2_star
      - jan_to_nov_2025_avg_rating
      - rating_change_pts
      Details: Join product_reviews (is_approved = true) to products to tenants, filtered to tenants.industry = 'Home & Living'. dec2025_review_count / dec2025_avg_rating / dec2025_pct_1_2_star are computed over approved reviews with created_at in December 2025 (2025-12-01 to 2025-12-31) for that merchant. jan_to_nov_2025_avg_rating is the same merchant's mean approved-review rating for created_at in January-November 2025 (2025-01-01 to 2025-11-30), used as a pre-dip baseline. rating_change_pts = dec2025_avg_rating minus jan_to_nov_2025_avg_rating, rounded to 2 decimals (more negative = bigger relative decline). Only include merchants with at least 1 review in December 2025. Round avg ratings to 2 decimals, pct to 1 decimal. Order by rating_change_pts ascending (biggest decline first), tie-break by dec2025_review_count descending.
      
      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,
             d.review_count AS dec2025_review_count,
             d.avg_rating AS dec2025_avg_rating,
             d.pct_1_2_star AS dec2025_pct_1_2_star,
             j.avg_rating AS jan_to_nov_2025_avg_rating,
             ROUND(d.avg_rating - j.avg_rating, 2) AS rating_change_pts
      FROM tenants t
      JOIN (
        SELECT p.tenant_id,
               COUNT(*) AS review_count,
               ROUND(AVG(pr.rating), 2) AS avg_rating,
               ROUND(100.0 * SUM(CASE WHEN pr.rating <= 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1_2_star
        FROM product_reviews pr
        JOIN products p ON pr.product_id = p.id
        WHERE pr.is_approved = true
          AND pr.created_at >= DATE '2025-12-01'
          AND pr.created_at < DATE '2026-01-01'
        GROUP BY p.tenant_id
      ) d ON d.tenant_id = t.id
      JOIN (
        SELECT p.tenant_id,
               ROUND(AVG(pr.rating), 2) AS avg_rating
        FROM product_reviews pr
        JOIN products p ON pr.product_id = p.id
        WHERE pr.is_approved = true
          AND pr.created_at >= DATE '2025-01-01'
          AND pr.created_at < DATE '2025-12-01'
        GROUP BY p.tenant_id
      ) j ON j.tenant_id = t.id
      WHERE t.industry = 'Home & Living'
      ORDER BY rating_change_pts ASC, d.review_count DESC
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: merchant_name, dec2025_review_count, dec2025_avg_rating, dec2025_pct_1_2_star, jan_to_nov_2025_avg_rating, rating_change_pts
    • FelixQuery compiles correctly. Submitting now.
    • Felix calls submit
      SELECT t.name AS merchant_name,
             d.review_count AS dec2025_review_count,
             d.avg_rating AS dec2025_avg_rating,
             d.pct_1_2_star AS dec2025_pct_1_2_star,
             j.avg_rating AS jan_to_nov_2025_avg_rating,
             ROUND(d.avg_rating - j.avg_rating, 2) AS rating_change_pts
      FROM tenants t
      JOIN (
        SELECT p.tenant_id,
               COUNT(*) AS review_count,
               ROUND(AVG(pr.rating), 2) AS avg_rating,
               ROUND(100.0 * SUM(CASE WHEN pr.rating <= 2 THEN 1 ELSE 0 END) / COUNT(*), 1) AS pct_1_2_star
        FROM product_reviews pr
        JOIN products p ON pr.product_id = p.id
        WHERE pr.is_approved = true
          AND pr.created_at >= DATE '2025-12-01'
          AND pr.created_at < DATE '2026-01-01'
        GROUP BY p.tenant_id
      ) d ON d.tenant_id = t.id
      JOIN (
        SELECT p.tenant_id,
               ROUND(AVG(pr.rating), 2) AS avg_rating
        FROM product_reviews pr
        JOIN products p ON pr.product_id = p.id
        WHERE pr.is_approved = true
          AND pr.created_at >= DATE '2025-01-01'
          AND pr.created_at < DATE '2025-12-01'
        GROUP BY p.tenant_id
      ) j ON j.tenant_id = t.id
      WHERE t.industry = 'Home & Living'
      ORDER BY rating_change_pts ASC, d.review_count DESC
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • FelixSubmitted. The report joins `product_reviews` → `products` → `tenants`, scoped to approved reviews in the Home & Living industry, with separate December 2025 and January–November 2025 aggregates per merchant, ordered by biggest rating decline first.