cswork / libraryOpen practice workspace

Interview guides · Walmart

Walmart Data Scientist Interview Questions & Guide 2026

Walmart data scientist prep on data pitfalls: selection bias, target leakage, and checking an outlier's provenance before you drop it.

The 60-second brief

This guide covers what a Data Scientist at Walmart is expected to do and how to prepare for the interview.

Most of the loop measures decision-making under uncertainty rather than recall. You are scored on whether you state your assumptions, commit to an estimate you can defend, and say explicitly what evidence would change it.

Focus areas

  • Join order, return and inventory grains without fan-out
  • Separate true demand from stockout-censored sales
  • Size promotions on incremental margin, not revenue

The Walmart interview process

Walmart candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Recruiter Screen

A screening call is a matching exercise run by someone who will not evaluate your statistics. They are checking that the work described on your resume is work you personally did, and that its scope matches the level the role is written for. Logistics get settled in the same half hour so nobody spends an interviewer's afternoon on a mismatch. The answer that fails is the one narrated in the plural. If every sentence is 'we built' and 'the team decided', there is nothing specific to write down about you. Name the piece that was yours, the decision you made inside it, and what changed after.

What to demonstrate

  • Whether the ownership implied by your resume survives one round of follow-up about who actually did which part
  • Whether your described scope (data size, stakeholders, what shipped) matches the seniority the role is written at
  • Whether timeline, location and compensation expectations make the rest of the loop worth scheduling

How to prepare

  • Rewrite your top three resume bullets in the first person singular, each with the decision you made and what moved afterwards, then say them out loud once so the 'we' does not return under pressure
  • Attach one number to each project: the baseline, the change, and the window it was measured over. Where impact was never measured, say that plainly rather than inventing a figure
  • Settle your compensation range before the call and give it as a range with a reason behind it, such as current total comp or a competing timeline, instead of deflecting the question twice

Technical Screen

Much of what gets scored here happens out loud while you type. Nobody can see your reasoning inside a half-written query, so five silent minutes read as being stuck even when they are not. State the plan in plain language first: which tables, what grain you are aggregating to, and the one filter that defines the population. Then write it. The narration doubles as insurance, because a wrong plan gets caught early and cheaply while a wrong query gets caught at the end with no time left to redo it. A timed statistics section, where one exists, is a separate test with its own clock.

What to demonstrate

  • Whether the query you write matches the plan you just described
  • What you do with a hint, meaning whether the correction gets absorbed or the first approach gets defended
  • Whether you can debug your own wrong output by reading the result set and naming which part of the query produced the anomaly

How to prepare

  • Solve three problems while screen-sharing into a recording, then watch it back and mark every stretch longer than thirty seconds where you said nothing
  • Practise compressing the plan into one sentence before typing, then check afterwards whether the finished query actually matched it
  • Time yourself on statistics questions that carry a business reading, such as what a confidence interval does and does not claim, rather than re-reading notes without a clock

Virtual Onsite Loop

Where a loop includes a partner from outside the data team, that conversation usually carries the same weight as the technical ones and gets the least preparation. The person opposite you will not follow a derivation and does not need to. They are working out whether having you involved would make their decisions better or slower. The failure mode is not being too technical. It is answering a question about a decision with a description of your method, leaving the translation to them. What they carry into the debrief is the sentence you handed them, not the analysis underneath it.

What to demonstrate

  • Whether a statistical result arrives as something the partner could act on, with the one caveat that would change their decision kept and the rest left out
  • Whether you can state what you need from their side, in their terms: instrumentation that does not exist yet, a definition they own, or a holdout they have to agree to
  • Whether uncertainty is given as a range someone can plan against, rather than as hedging that invites them to ignore the result
  • Whether you ask what decision is actually on the table before explaining anything

How to prepare

  • Take a result you know well and write the version for someone who stops reading after one sentence, then the three-minute version, and check the short one is not the long one with the qualifications stripped out
  • For a past project, list everything you asked a non-technical partner for and how you phrased it, then rewrite each ask so it names what goes unmeasured without it
  • Practise saying where a result does not apply, out loud, in one sentence that a partner could repeat accurately to someone else

Where candidates lose points

Crediting promotions and channels by last click, especially coupon codes

A discount code handed to a partner or an influencer is claimed by customers who were already at checkout, so last-click attribution books organic demand as partner-driven, and the reported return on that spend is an artefact of the code's visibility at the basket rather than of any persuasion. The same mechanism makes email and paid search look strong because they sit close to a purchase that other activity created. Incremental effects need a holdout, a geo split or a switched-off period; where none is possible, at minimum report the share of code redemptions from customers whose session began before any partner touchpoint, because that number alone usually collapses the claim.

Comparing average order value across a change that alters basket composition

Free-shipping thresholds, multi-buy offers and minimum-spend coupons make customers bunch their basket just above a cut-off, so average order value moves because the mix of orders changed, not because anyone is spending more per item. The same trap appears when a change suppresses small orders: average order value rises while total revenue falls. Decompose into units per order and price per unit, look at the whole basket-value distribution rather than the mean (the bunching is visible as a spike at the threshold), and evaluate the change on revenue per session rather than on the conditional mean of orders that happened.

Answering a product-sense question with a list of features

Answer with a decision and the measurement that would settle it: the hypothesis, the primary metric, the guardrails, and the result that would make you not ship. A feature brainstorm cannot be wrong, which is exactly why it earns no points.

SQL that silently fans out on a one-to-many join

State the grain of each table and the grain you want in the result before writing the join. Pre-aggregate the many side to the join key, or use EXISTS or a window function, and verify with a row count against COUNT(DISTINCT id) rather than trusting that the numbers look plausible.

Questions & practice

How do you select appropriate priors and interpret posterior distributions in Bayesian A/B testing frameworks?

Medium · statistics and probability

Approach

  1. Translate the result into the decision it informs, in one plain sentence.
  2. Say what the estimate is of, and over what population it generalises.
  3. Write down the assumption the method needs before you use the method.

Follow-up

  • How would you explain this result to someone who does not know statistics?
  • What sample size would you need to detect an effect half this size?

If a newly launched recommendation algorithm increases click-through rate but decreases average order value, how do you decide whether to roll it out?

Medium · machine learning and modelling

Approach

  1. Say how the offline result would be validated online before it is trusted.
  2. Frame the prediction: the label, the moment of prediction, and the action it triggers.
  3. Set a baseline first, so any model has something honest to beat.

Follow-up

  • How would you choose the decision threshold, and who owns that choice?
  • What would you monitor after launch to know the model is still valid?

Write a data-quality checker for order and return lines

Medium · data quality · invariants · pandas · grain

Given order_lines (order_line_id, order_id, sku_id, quantity, unit_list_price_cents, unit_paid_price_cents, line_discount_cents, placed_at_utc, shipped_at_utc, delivered_at_utc, cancelled_at_utc, line_status, fx_rate_to_usd) and return_lines (return_line_id, order_line_id, quantity_returned, refund_amount_cents, initiated_at_utc, return_reason), write a checker that returns one row per check with check_name, severity, n_failing, pct_failing and up to five example ids. Cover key uniqueness, timestamp ordering, status-timestamp agreement, over-refund, and cumulative returned quantity exceeding the quantity ordered.

Approach

  1. Write each check as a function returning a boolean mask over a named frame, then run them through one driver that assembles the report. Uniform shape is what lets you add a check later without touching the reporting code.
  2. Separate row-level checks from aggregate checks. Over-refund on a single return row is row-level; cumulative quantity_returned per order_line_id exceeding the ordered quantity only exists after a groupby, and a row-wise checker will pass a line returned twice for its full quantity.
  3. Encode the status contract explicitly: delivered requires delivered_at_utc non-null and cancelled_at_utc null; cancelled_out_of_stock requires cancelled_at_utc and forbids shipped_at_utc; placed forbids all three. Ordering checks must skip nulls rather than treat a null as failing, since a line legitimately has no delivered_at_utc until it lands.
  4. Assign severity by what the failure does downstream, not by how alarming it looks. A duplicate order_line_id double-counts revenue and blocks a metric refresh; a return initiated before delivery is expected for a refused delivery and belongs at warning with return_reason reported alongside.
  5. Report pct_failing against an explicit denominator per check, because the denominator differs: uniqueness runs over all lines, the delivery ordering check only over lines with a delivered timestamp.

Worked solution (30 min)

  1. Implement checks: duplicate order_line_id; placed_at_utc <= shipped_at_utc <= delivered_at_utc among non-null pairs; status-timestamp agreement per the contract above; unit_paid_price_cents > unit_list_price_cents while line_discount_cents > 0; fx_rate_to_usd <= 0 or null.
  2. Implement the aggregate check: group return_lines by order_line_id, sum quantity_returned, join to order_lines, flag sum > quantity.
  3. Implement over-refund: refund_amount_cents > quantity_returned * unit_paid_price_cents on the joined row, allowing an explicit tolerance for tax if a tax column is in scope.
  4. Assemble the report with a consistent example-id column and sort by severity then n_failing descending.
  5. Seed a fixture with one known violation of each check and assert the report finds exactly those counts.

Expected result: A DataFrame with one row per check, in which a seeded fixture containing exactly one violation per check reports n_failing equal to 1 for each, and the multi-RMA overflow check fires on a line with two return rows of one unit each against an ordered quantity of one.

Verify it yourself

  • Running the checker on a clean fixture returns all zeros rather than an empty frame, so a silently dropped check is visible
  • Each check's denominator is reported and matches the population it can apply to
  • Null timestamps do not count as ordering failures
  • The aggregate check fires on the two-RMA fixture while every row-wise check passes it

Follow-up

  • Which of these checks would you run as a hard gate before the nightly metric refresh, and which would you only alert on? Defend the boundary.
  • The cumulative returned quantity exceeds the ordered quantity on 0.2 percent of lines. Name two upstream mechanisms that produce this legitimately and two that are bugs.
  • How would you turn this into a trend rather than a snapshot, and what threshold would trigger a page?

Explain how you would use pandas to reshape, pivot, and impute missing values in a messy telemetry dataset during a live coding screen.

Medium · sql and data manipulation

Approach

  1. Check whether any join is one-to-many before aggregating, or the sums inflate.
  2. Say which table is the grain you start from, and join outward from it.
  3. Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.

Follow-up

  • How does the query change if the join becomes one-to-many?
  • What breaks if events arrive late or out of order?

Write a query using SQL window functions to calculate rolling 7-day average sales per store, handling missing dates gracefully.

Medium · sql and data manipulation

Approach

  1. Compute rates by summing numerator and denominator separately, never by averaging rates.
  2. Say which table is the grain you start from, and join outward from it.
  3. Check whether any join is one-to-many before aggregating, or the sums inflate.

Follow-up

  • How does the query change if the join becomes one-to-many?
  • What breaks if events arrive late or out of order?

Daily visit-to-order conversion by device, excluding denied-consent sessions

Easy · funnel · aggregation · null handling

From fct_session (session_id, started_at_utc, device_type, entry_channel, order_id, tracking_consent, is_bot_flagged), return visit-to-order conversion for the last 28 days split by device_type and entry_channel. A session converts when order_id IS NOT NULL. Exclude is_bot_flagged = TRUE, and exclude tracking_consent = 'denied' from both numerator and denominator, reporting the denied share of non-bot sessions as its own column. Then produce the weekly figure from the same base. Output: day or week, device_type, entry_channel, sessions, orders, conversion_rate, denied_share.

Approach

  1. Filter once in a base CTE (is_bot_flagged = FALSE, started_at_utc in the window) and carry tracking_consent through, so the numerator and denominator can never drift apart in two separate scans.
  2. Aggregate with conditional counts in a single pass: COUNT(*) FILTER (WHERE tracking_consent <> 'denied') as sessions, and the same filter plus order_id IS NOT NULL as orders.
  3. Divide at the end with a NULLIF on the denominator and a numeric cast, because integer division floors a 2 percent rate to 0.
  4. For the weekly number, group the same base on date_trunc('week', started_at_utc) and re-divide the summed counts; an average of seven daily rates weights a quiet Tuesday the same as a peak Saturday.
  5. Emit denied_share = denied sessions / all non-bot sessions beside the rate, so a consent-banner change that moves the denominator is visible rather than being read as a behaviour change.

Worked solution (20 min)

  1. Write the base CTE with the bot filter and the date window, selecting session_id, started_at_utc, device_type, entry_channel, order_id, tracking_consent.
  2. Add the grouped aggregate with FILTER clauses for sessions, orders and denied sessions.
  3. Compute conversion_rate = orders::numeric / NULLIF(sessions, 0) and denied_share = denied::numeric / NULLIF(sessions + denied, 0).
  4. Duplicate the aggregate with date_trunc('week', started_at_utc) as the grain and confirm the weekly rate is derived from summed counts.
  5. Compute both weekly figures side by side and the covariance between daily sessions and daily rate, so the size of the gap is a measured number rather than an assumption.
  6. Spot-check one device and channel by hand for a single day against a raw COUNT.

Expected result: One row per (day, device_type, entry_channel) with sessions, orders, a conversion_rate between 0 and 1, and denied_share. The weekly rate equals SUM(orders)/SUM(sessions), and it exceeds the unweighted mean of the seven daily rates by exactly Cov(daily sessions, daily rate) / mean(daily sessions), the covariance taken over the seven days. So the two agree whenever the daily rates are flat, or whenever volume and rate are uncorrelated, however wide the traffic spread; they diverge only when volume and rate move together, which is the usual shape of a promotional weekend. Measure the gap on the actual week rather than asserting it is negligible or large.

Verify it yourself

  • SUM(sessions) across all rows for a day equals the count of non-bot, non-denied sessions started that day.
  • orders never exceeds sessions in any row.
  • The difference between the two weekly figures matches Cov(sessions, rate) / mean(sessions) to rounding, which confirms the gap is the volume-rate relationship and not an aggregation bug.
  • Replacing the seven daily rates with their mean (holding sessions fixed) collapses that difference to zero, which is the control that proves traffic dispersion alone does not create it.
  • denied_share summed with the retained share equals 1 for every day.

Follow-up

  • Denied-consent sessions can still place orders. What does excluding them do when you reconcile session-attributed orders against total orders in fct_order_line, and how do you present that gap?
  • Conversion rose on desktop and rose on mobile_web, but the blended rate fell. What happened, and what would you show to make it obvious?
  • How would you handle a session that starts at 23:55 and places its order at 00:04 the next day?

Walk through your diagnostic framework when a core business metric experiences an unexpected 15% drop overnight.

Medium · product sense and metrics

Approach

  1. Name one primary metric, then the guardrail that stops it being gamed.
  2. Restate the decision this analysis has to support, and who acts on the answer.
  3. Fix the population and the time window before naming any metric.

Follow-up

  • What would you do if the primary metric and the guardrail moved in opposite directions?
  • Which segment would you cut first, and what would that rule out?

How do you isolate whether a conversion rate drop is driven by traffic mix changes or conversion efficiency loss?

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Decompose the metric into the rates that drive it, and say which one you would check first.
  3. Fix the population and the time window before naming any metric.

Follow-up

  • How would you detect that the metric is being gamed rather than genuinely improving?
  • Which segment would you cut first, and what would that rule out?

What framework would you use to evaluate the success of an in-store digital kiosk pilot project?

Medium · product sense and metrics

Approach

  1. Restate the decision this analysis has to support, and who acts on the answer.
  2. State what result would change your recommendation, so the answer is falsifiable.
  3. Decompose the metric into the rates that drive it, and say which one you would check first.

Follow-up

  • What would you do if the primary metric and the guardrail moved in opposite directions?
  • How would you detect that the metric is being gamed rather than genuinely improving?

How would you handle a situation where an experiment shows statistically significant positive results on secondary metrics but flat primary metrics?

Medium · product sense and metrics

Approach

  1. Restate the decision this analysis has to support, and who acts on the answer.
  2. Fix the population and the time window before naming any metric.
  3. Decompose the metric into the rates that drive it, and say which one you would check first.

Follow-up

  • What would you do if the primary metric and the guardrail moved in opposite directions?
  • How would you detect that the metric is being gamed rather than genuinely improving?

Explain how you would design a quasi-experimental method, such as causal impact or difference-in-differences, when traditional A/B testing is impossible in physical store locations.

Medium · a/b testing and experimentation

Approach

  1. State the primary metric and the minimum effect worth shipping, then size the test.
  2. Decide the analysis before seeing data, including how long it runs and when you look.
  3. Name the guardrails that would stop a launch even on a positive primary result.

Follow-up

  • How would you handle interference between treated and control units?
  • What would you conclude if the result is positive but the test is underpowered?

What are the most common experimentation pitfalls you look out for when analyzing retail experiments, such as sample ratio mismatch or novelty effects?

Medium · a/b testing and experimentation

Approach

  1. Decide the analysis before seeing data, including how long it runs and when you look.
  2. Name the randomisation unit first; it decides the variance and what the test can detect.
  3. Name the guardrails that would stop a launch even on a positive primary result.

Follow-up

  • How would you handle interference between treated and control units?
  • What would you do if you could not randomise at all?

How would you define key performance indicators for an automated supply chain forecasting dashboard?

Medium

Approach

  1. Say what you would check first and why it is the highest-information step.
  2. Work from the decision backwards to the evidence you would need.
  3. Clarify what is being asked and what a complete answer would contain.

Follow-up

  • What assumption would you test first?
  • How would you know your answer was wrong?

Choose the randomisation unit for a signed-out surface

Medium · randomisation unit · clustering · contamination

You are testing a size-guide module that is visible to signed-out visitors. Exposure can be keyed on fct_session.session_id, fct_session.anonymous_id, dim_customer.customer_id or dim_customer.household_id. Note that fct_session.customer_id is NULL until sign-in, fct_order_line rows from channel 'store_pos' and 'subscription_autoship' carry session_id NULL, and household_id is non-null for 28 percent of accounts with mean household size 1.4. The primary metric is net revenue per exposed visitor over 30 days. Choose the unit, state what each rejected option breaks, and quantify the variance cost of your choice.

Approach

  1. Rule out session_id first: a 30-day outcome spans many sessions, so a visitor would be re-randomised on every visit, diluting the contrast toward zero and breaking the independence the variance estimate assumes.
  2. Rule out customer_id for exposure: it is NULL until sign-in, so a customer-keyed assignment cannot be resolved at the moment the signed-out visitor sees the module. It remains the right unit for a signed-in-only surface.
  3. Pick anonymous_id as the assignment key, then confront its two leaks. The same person on desktop and on ios_app holds two anonymous_ids and can land in both arms, which attenuates the effect; and orders arriving through store_pos or subscription_autoship carry session_id NULL, so their revenue cannot be attributed to any arm.
  4. Handle the unattributable revenue explicitly: measure the share of net revenue that cannot be keyed back, confirm it is similar in both arms, and report the estimate as conditional on web-attributable revenue rather than quietly dropping it.
  5. Handle households by assigning every anonymous_id sharing a household_id to the same arm where the link is known, and clustering standard errors on household_id. Price the cost with the design effect 1 + (m-1) * ICC so the sample increase is a number, not a worry.

Worked solution (30 min)

  1. Assign on anonymous_id, held for the full 30-day window in a persistent bucket rather than recomputed per session.
  2. Force household consistency: where dim_customer.household_id is non-null, take the arm of the first assigned member for all members.
  3. Compute the design effect with mean cluster size 1.4 and an assumed intra-household correlation of 0.3: 1 + (1.4 - 1) * 0.3 = 1.12.
  4. Inflate the per-arm sample by 12 percent and cluster the standard errors on household_id where present, on anonymous_id otherwise.
  5. Report the attribution gap: the percentage of net revenue from store_pos and subscription_autoship lines with session_id NULL, split by arm, as a pre-declared balance check.

Expected result: Assign on anonymous_id with household-consistent buckets and household-clustered standard errors; a design effect of 1.12 means 12 percent more exposed visitors for the same power. Revenue on lines with session_id NULL is excluded and reported separately with its arm split.

Verify it yourself

  • Sanity-check the ICC empirically on pre-period data: regress one household member's 30-day revenue on another's and confirm the correlation is near the assumed 0.3.
  • Confirm the arm assignment is stable by counting anonymous_ids that appear in both arms across the window; that count should be zero.
  • Confirm the unattributable revenue share differs by less than a percentage point between arms, otherwise the exclusion is itself a source of bias.

Follow-up

  • Cross-device contamination attenuates the measured effect. If 18 percent of exposed visitors see both arms, what does that do to the estimate, and does it make the test conservative or anti-conservative?
  • How would you decide whether to reconcile anonymous_id to customer_id retrospectively after sign-in, given that the reconciliation itself is only possible for visitors who converted?

A category looks down and the buy is about to be cut

Hard · censoring · stockouts · forecasting

Units sold in one category are down 14% over six weeks, and the statistical forecast built on that sales history now recommends cutting next season's buy by roughly the same amount. You have fct_inventory_snapshot (snapshot_date, sku_id, node_id, was_listed, minutes_unavailable, available_to_promise_units, on_hand_units, forecast_units, gross_units_sold, units_cancelled_oos) and fct_order_line (sku_id, quantity, line_status). Deliverable: quantify how much of the 14% is demand censored by availability, state the assumptions behind your lost-units estimate, and say whether the buy cut is defensible.

Approach

  1. Establish availability as a series before touching the forecast. Compute demand-weighted in-stock rate per week for the category using forecast_units * (1440 - minutes_unavailable) / 1440 over forecast_units, restricted to was_listed = TRUE, and count SKU-days with minutes_unavailable > 0. A concurrent availability decline is a flag, not proof, so keep it as evidence rather than a conclusion.
  2. Run a like-for-like comparison that removes the censoring by construction: restrict both periods to SKU-days with minutes_unavailable = 0 and was_listed = TRUE, on SKUs present in both windows. If the like-for-like decline is a small fraction of 14%, most of the headline gap is availability rather than demand.
  3. Estimate lost units explicitly. For each SKU-day with an outage, scale that SKU's in-stock daily rate by the unavailable fraction of the day, and add units_cancelled_oos plus lines with line_status = 'cancelled_out_of_stock' as an independent, directly observed floor. State the assumption that demand is uniform within the day, and that an end-of-day snapshot cannot see a SKU that sold out at mid-morning and was replenished overnight.
  4. Do not treat the SKU-level sum as the category loss. Substitution moves some of those units to an in-stock sibling SKU and would be double counted, so net the estimate against sibling uplift during outage windows; in the other direction, demand suppressed before it was ever recorded, from customers who saw an empty category and left, is not in this data at all. Give a range and name both directions.
  5. Rule out the alternatives that would survive the correction: price or promotional changes in the window, listings suppressed with stock on hand (was_listed = FALSE while on_hand_units > 0, which is a merchandising fault not a supply one), and category page traffic.
  6. Recommend on the corrected series, and state the modelling fix: refit on in-stock periods only, carry availability as an exposure term, or use a censored likelihood, each of which needs availability history retained at a finer grain than a daily end-of-day snapshot.

Follow-up

  • You only have end-of-day snapshots plus minutes_unavailable. Which of your three modelling fixes survives that, and what do you lose?
  • The cost of a lost sale and the cost of an end-of-season markdown unit are not equal. How does that change the quantile you forecast to?
  • Half the SKUs in this category are new this season with no history. How do you forecast them, and how do you validate that approach before the buy is committed?

Suggested practice checklist

For someone who has spent the last year in notebooks, dashboards or modelling work and has not written raw SQL under time pressure. The first four days rebuild query fluency against a fixture you control and can verify by hand; the last three attach that fluency to the rest of the loop.

Day 1 — Build a fixture you can check answers against

  • Create a local Postgres or SQLite database with four tables (users, sessions, events, orders) holding roughly 200 rows you generated yourself, so you know the contents well enough to predict every result.
  • Deliberately seed the cases that break queries: a user with no sessions, a session with no events, two orders sharing a timestamp, a NULL in one join key, and one duplicated user row.
  • Before writing any SQL, hand-compute five answers on paper (how many users placed at least one order, median orders per ordering user, and three others) and save them as the ground truth for the week.

Deliverable: A one-command seed script plus a text file of five hand-computed answers to grade every later query against.

Day 2 — Joins, filters and NULL semantics

  • Answer "which users have no orders" three ways (LEFT JOIN with IS NULL, NOT EXISTS, NOT IN) and confirm that the NOT IN version returns zero rows once the subquery contains a NULL, because the comparison is never TRUE.
  • Reproduce the LEFT JOIN that silently collapses to an inner join by putting a right-table predicate in WHERE, then fix it by moving the predicate into the ON clause, and record both row counts.
  • Create a fan-out bug on purpose by joining orders to order_items and summing the order total, then correct it with a pre-aggregated subquery and explain in one line which table changed the grain.

Deliverable: One annotated .sql file holding the three join traps, each with the wrong result and the corrected result side by side.

Day 3 — Window functions and frames

  • Write three window queries against the fixture: a running order total per user, the rank of each order within its user by value, and the day gap to that user's previous order, then check each against the day-one ground truth.
  • Run ROW_NUMBER, RANK and DENSE_RANK over a column containing ties, print all three side by side, and write one sentence on when each is the correct choice.
  • Switch one query from the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, which is what you get when ORDER BY is present and no frame is written) to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and explain why the output differs only when the ORDER BY column has duplicates.

Deliverable: Three verified window queries plus a short note explaining the RANGE versus ROWS difference in your own words.

Day 4 — The four analytical query patterns

  • Write a monthly retention grid: first order month per user, then months-since-first as the column, and verify that month zero equals the cohort size exactly.
  • Sessionize the events table under a 30-minute inactivity rule using LAG plus a cumulative sum over a new-session flag.
  • Build a four-step funnel that counts distinct users rather than events at each step, and state the rule you applied to a user who reaches step three without ever logging step two.

Deliverable: One file with the retention, sessionization and funnel patterns, each carrying a one-line note on the assumption it bakes in.

Day 5 — Write SQL the way you will have to write it live

  • Set a 12-minute timer and solve three medium prompts in a plain editor with no execution and no autocomplete, then run them and tally syntax errors separately from logic errors.
  • Narrate one solution aloud while writing it, stating the grain of each intermediate result (one row per user, one row per user-day) before you type its body.
  • Rewrite your slowest solution as a CTE chain where every CTE name states its grain, and time yourself re-solving it from blank.

Deliverable: A recording of one narrated solution plus an error tally that separates syntax from logic.

Day 6 — One day for everything that is not SQL

  • Write the preconditions of the two-sample t-test from memory, then check them: independent observations, and a difference in means whose sampling distribution is approximately normal, which at large sample sizes follows from the central limit theorem rather than from normality of the raw values.
  • Write the difference between an odds ratio from logistic regression and a relative risk, and state the condition under which the two are close (low outcome prevalence).
  • Prepare a 90-second answer to "how would you know this model is any good" that names the metric, the baseline you would beat, and the cost of the errors you care about.

Deliverable: One page of notes covering test preconditions, the odds-ratio caveat and the model-quality answer.

Day 7 — Full loop rehearsal

  • Run a 45-minute mock with someone willing to interrupt: 20 minutes of SQL, 15 minutes defining a metric, 10 minutes on a past project.
  • Re-solve from blank the two queries you were slowest on this week and compare the times against day five.
  • Write a five-line answer to "walk me through a project" that puts a number in the first sentence and names the decision the work changed.

Deliverable: Mock feedback notes plus a timed project narrative you can deliver without reading it.

What the behavioural round is actually scoring

Interviewers here are not checking whether you can describe a project. They want the decision you made, why you made it under the information you had, and what changed afterwards that someone else could measure. A story that ends at 'I built a model' has no ending. Say what the model caused, or what you stopped doing because of it.

Tell me about a time you disagreed with a senior engineering or product decision. How did you resolve the conflict?

Medium · behavioural and stakeholder questions

Approach

  1. State the situation in two sentences and spend the rest on your reasoning.
  2. Close with what you would do differently, concretely.
  3. Pick a story where you drove the decision, not one where you observed it.

Follow-up

  • What would you do differently if you ran that project again?
  • How did you know the outcome was caused by your change?

Disagree with a product manager about a recommendation slot

Medium · surface metrics · holdout analysis · disagreement

A product manager wants to ship a recommendation module that raised slot click-through by thirty-one percent and slot-attributed revenue by nineteen percent over a two-week test. You have the holdout and can compute site-wide net revenue per session. Over the same window the treatment arm shows a higher net unit return rate and higher promotional depth on purchased lines, and site-wide revenue per session is flat within noise. The product manager has a launch date. Present your position in a fifteen-minute meeting and state what you recommend.

Approach

  1. Concede the surface result rather than disputing it. Click-through did rise. The open question is whether the units are new or moved from a search result, another slot or a later visit.
  2. State the measurement claim in one sentence: slot-attributed revenue counts capture, and only the holdout prices the counterfactual of what those customers would have bought anyway.
  3. Give the site-wide read with an interval, and say whether the test was powered to detect the effect size being claimed. Flat within noise is not evidence of no effect, and treating it as such is the fastest way to lose the argument to someone who notices.
  4. Bring the two mechanisms that explain the gap and point at where they are visible: the module surfaces more apparel and more discounted stock, which moves quantity_returned in fct_return_line and line_discount_cents in fct_order_line.
  5. Recommend something shippable this week rather than a block: launch behind a holdout that stays on, with site-wide net revenue per session after returns as the read at return maturity, and the decision rule agreed now.

Follow-up

  • The product manager says returns take ninety days and the launch cannot wait. What do you ship on in the meantime?
  • What result would make you say the module is working?

Tell a team their test cannot be read before Friday

Hard · power · skewed metrics · return maturity

A checkout test has run eleven days. Conversion is 2.4 percent in control and 2.7 percent in treatment, and the team wants to ship on Friday. Revenue per visitor is higher in treatment, driven by a small number of very large baskets, and the return window on those orders has not closed. The engineering lead has already announced the win internally. You are asked for sign-off. Give your answer, the evidence behind it, and a path that lets them ship without pretending the result is something it is not.

Approach

  1. Compute rather than assert. State the minimum detectable effect the observed sample supports at a 2.4 percent baseline, then say whether a 0.3 point absolute lift sits inside or outside it. An objection without that number reads as caution and loses to a launch date.
  2. Separate the two problems, because they have different fixes. Conversion may simply be underpowered. Revenue per visitor is a different failure: the mean is driven by the tail, so it needs a cap declared before the data was seen or a bootstrapped interval, and a cap chosen now is not a cap.
  3. Run the mechanical checks first because they are cheap and they end arguments: sample ratio mismatch, the triggered-population definition, and whether both arms drew on the same constrained inventory.
  4. Quantify the return exposure concretely: the share of treatment revenue sitting in orders whose return window is open, and what the category's matured net unit return rate would do to the lift if applied to it.
  5. Offer a path rather than a veto. If the change is reversible and the downside is bounded, ship it, with the read scheduled at return maturity and the decision rule written down now, before anyone knows which way it goes.
  6. Handle the premature announcement quietly and separately. It is a fact to correct, not a position to negotiate against, and making it the topic guarantees the measurement argument is lost.

Follow-up

  • The team says the large baskets are real revenue and capping throws away the win. What is your answer?
  • What decision rule would you write down today so this same conversation does not happen on the next test?