← DoorDash Interview Insights

DoorDash·Data Scientist·Take-home Assignment·Senior

Senior
Apr 2026

Summary

DoorDash data science take-home with a pretty dense SQL prompt built around their core domain: orders, dashers, merchants, promos. Six sub-questions covering window functions, anomaly detection, uplift estimation, and even a bootstrap CI question at the end. Felt more like a mini-project than a screening filter.

Questions Asked (6)

Q1

Given a multi-table delivery schema, compute the daily on-time delivery rate per city over a rolling 7-day window. Define on-time as delivery within 45 minutes of order creation, treating null delivered_at as late and excluding canceled orders. Return city, date, on-time count, total eligible, and rate.

Product Analytics & MetricsData Modeling
Author's notes

The null delivered_at edge case is the part I almost missed.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the schema and business rules, then outline a SQL-based solution using CTEs to filter eligible orders, compute delivery times, and aggregate daily metrics. Finally, apply a rolling 7-day window per city using window functions, ensuring correct handling of nulls and canceled orders.

Pro tip: Explicitly state your assumptions about the schema and edge cases (e.g., time zones, order status definitions) before diving into code; this shows you think like a data scientist who cares about data quality and stakeholder alignment.

1. Clarify schema and business logic

Identify relevant tables (orders, deliveries, cities) and confirm definitions: on-time threshold, null handling, canceled orders, and time zone considerations.

2. Filter and prepare base data

Exclude canceled orders, join necessary tables, and compute delivery duration (delivered_at - created_at) for each order, marking on-time status.

3. Aggregate daily metrics per city

Group by city and order date to calculate daily on-time count and total eligible orders, then compute the daily on-time rate.

4. Apply rolling 7-day window

Use window functions to compute rolling sums of on-time and total counts over the past 7 days per city, then derive the rolling rate.

5. Validate and present results

Check for edge cases (e.g., cities with no orders on some days), ensure correct date alignment, and format the final output with city, date, counts, and rate.

Key Points to Mention

  • Handling null delivered_at as late deliveries
  • Excluding canceled orders from the eligible population
  • Using window functions (e.g., ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) for rolling 7-day calculations
  • Ensuring date granularity and time zone consistency
  • Computing rate as on-time count divided by total eligible, with proper null handling
  • Considering performance implications for large datasets (e.g., partitioning by city and date)

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

For a given month, rank the top 3 merchants per city by GMV, where GMV accounts for subtotal, delivery fee, tip, and any applied promo discount. Break ties by cancellation count ascending, then by merchant ID. Exclude canceled orders from GMV but still track cancellations per merchant.

Product Analytics & MetricsData Modeling
Author's notes

Tie-breaking in window functions always trips me up a bit.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the exact definition of GMV and how to handle cancellations, then outline a two-part aggregation: one for GMV (excluding canceled orders) and one for cancellation counts (including all orders). Use a window function to rank merchants within each city, applying the tie-breakers, and finally filter to the top 3 per city.

Pro tip: Explicitly state that you would validate the results by checking edge cases, such as cities with fewer than 3 merchants or ties that require the secondary sort, and mention that you'd confirm the promo discount is subtracted from GMV (not added).

1. Clarify definitions and assumptions

Confirm that GMV = subtotal + delivery fee + tip - promo discount, and that canceled orders are excluded from GMV but included in cancellation counts. Ask about the time zone and whether 'given month' refers to order date or delivery date.

2. Aggregate GMV and cancellations per merchant per city

Write a query that groups by city and merchant, summing GMV only for non-canceled orders, and counting all orders (or canceled orders) for the cancellation metric. Ensure the promo discount is applied correctly.

3. Rank merchants within each city

Use a window function like ROW_NUMBER() or RANK() with PARTITION BY city ORDER BY GMV DESC, cancellation_count ASC, merchant_id ASC. Explain the difference between ROW_NUMBER and RANK for ties.

4. Filter to top 3 per city and validate

Select only rows where the rank is <= 3. Validate by checking a few cities manually and ensuring no city has more than 3 merchants in the output.

Key Points to Mention

  • GMV calculation: subtotal + delivery fee + tip - promo discount
  • Exclusion of canceled orders from GMV but inclusion in cancellation count
  • Use of window functions (e.g., ROW_NUMBER) with PARTITION BY city and ORDER BY GMV DESC, cancellation_count ASC, merchant_id ASC
  • Handling ties: ensure deterministic ordering with merchant_id as final tie-breaker
  • Potential data issues: nulls in promo discount, negative GMV, or missing city/merchant IDs
  • Performance considerations: indexing on city, merchant_id, and order date for large datasets

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Using an order events log table, identify orders that have a 'delivered' event but no 'picked_up' event that strictly precedes it in time. Return the order ID and a minimal event timeline showing the anomaly.

Root Cause AnalysisData Modeling
Author's notes

This one was actually kind of fun.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a self-join or window functions to compare each order's 'delivered' event against its 'picked_up' events, filtering for orders where no 'picked_up' event occurs before the 'delivered' event. Then, for those orders, extract a minimal timeline showing the relevant events (e.g., the delivered event and any picked_up events that occur after or not at all).

Pro tip: Clarify the definition of 'strictly precedes'—if timestamps are equal, it does not count as preceding. Also, consider edge cases like multiple delivered events or missing picked_up events entirely, and mention how you'd handle them.

1. Understand the data and requirements

Examine the schema of the order events log table, including columns like order_id, event_type, and timestamp. Clarify that 'strictly precedes' means timestamp < delivered timestamp, and that we need orders with a 'delivered' event but no 'picked_up' event before it.

2. Identify orders with delivered events

Filter the table for rows where event_type = 'delivered' to get a list of orders that have at least one delivered event. Note the delivered timestamp for each such order.

3. Check for preceding picked_up events

For each delivered order, check if there exists any 'picked_up' event with a timestamp strictly less than the delivered timestamp. Use a left join or NOT EXISTS subquery to find orders where no such picked_up event exists.

4. Construct minimal event timeline

For the anomalous orders, select the delivered event and any picked_up events (if any) that occur after the delivered event or at the same time, to show the anomaly. If no picked_up events exist, just show the delivered event.

5. Validate and present results

Double-check edge cases (e.g., multiple delivered events, null timestamps) and ensure the query returns the expected orders. Present the order ID and timeline clearly, explaining the anomaly.

Key Points to Mention

  • Use of SQL window functions (e.g., MIN, MAX) or self-joins to compare event timestamps within each order.
  • Handling of ties: 'strictly precedes' means timestamp < delivered timestamp, so equal timestamps do not count.
  • Edge cases: orders with multiple delivered events, missing picked_up events, or null timestamps.
  • Efficiency considerations: indexing on order_id and event_type, and avoiding full table scans.
  • Business impact: such anomalies may indicate data pipeline issues, app bugs, or process gaps, and should be investigated.
  • Clear communication of the anomaly timeline to stakeholders, possibly with a simple visualization.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Calculate a weekly dasher acceptance rate: for orders created in a given ISO week and assigned to a dasher, what share had an accepted_at timestamp within 3 minutes of created_at? Exclude orders canceled before acceptance. Output dasher_id, ISO week start, assigned order count, accepted-within-3m count, and rate.

Product Analytics & MetricsData Modeling
Author's notes

ISO week start tripped me up for a second.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the metric definition and edge cases, then outline a SQL query that joins orders and dasher assignments, filters out cancellations before acceptance, and computes the rate per dasher per ISO week. Emphasize correct handling of timestamps, week boundaries, and the denominator.

Pro tip: Mention that you would validate the metric by checking for anomalies like dashers with very low assigned order counts, and consider whether to set a minimum threshold for statistical significance. Also, note that timezone should be consistent (e.g., UTC) to avoid week boundary issues.

1. Clarify requirements and edge cases

Confirm definitions: what constitutes an 'assigned' order, how to identify cancellations before acceptance, and whether to include orders with no dasher assignment. Discuss timezone handling for ISO weeks.

2. Identify relevant tables and fields

Locate tables containing order creation, assignment, acceptance, and cancellation timestamps. Ensure you have dasher_id, order_id, created_at, accepted_at, and cancellation status.

3. Write SQL query with filters and aggregation

Filter orders to those assigned to a dasher and not canceled before acceptance. Compute time difference between accepted_at and created_at, flag those within 3 minutes, then group by dasher_id and ISO week of created_at.

4. Calculate and format output

Compute assigned order count, accepted-within-3m count, and rate as a decimal or percentage. Ensure ISO week start date is correctly derived (e.g., using DATE_TRUNC('week', created_at)).

5. Validate and interpret results

Check for data quality issues, such as missing timestamps or negative time differences. Consider if the rate should be weighted or if minimum order counts are needed for reliable comparison.

Key Points to Mention

  • Definition of 'assigned' order: likely an order that has a dasher_id and was not unassigned before acceptance.
  • Exclusion of orders canceled before acceptance: need to filter out orders where cancellation timestamp is before accepted_at or where accepted_at is null and order was canceled.
  • ISO week handling: use DATE_TRUNC('week', created_at) to get week start (Monday) and ensure timezone consistency.
  • Time difference calculation: accepted_at - created_at <= interval '3 minutes'.
  • Aggregation: COUNT(DISTINCT order_id) for assigned orders, SUM(CASE WHEN accepted_within_3m THEN 1 ELSE 0 END) for numerator, and rate as numerator/denominator.
  • Potential data quality checks: negative time differences, missing accepted_at for non-canceled orders, and dashers with very few orders.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

Find customers who have placed exactly two lifetime orders and both were canceled. Return the customer ID and both canceled_at timestamps in ascending order.

Product Analytics & Metrics
Author's notes

Straightforward HAVING COUNT = 2 and COUNT(CASE WHEN canceled) = 2.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a two-step aggregation: first, count total orders and canceled orders per customer, then filter for customers with exactly two total orders and two canceled orders. Finally, retrieve the canceled_at timestamps for those customers and order them ascending.

Pro tip: Clarify whether 'lifetime orders' includes only completed orders or all orders, and confirm that 'canceled' refers to orders with a non-null canceled_at timestamp. Also, consider edge cases like customers with exactly two orders where both are canceled but one might have a null canceled_at due to data issues.

1. Understand the data model

Identify the relevant tables (e.g., orders, customers) and columns (customer_id, order_id, canceled_at). Clarify definitions: what constitutes an order, and how cancellations are recorded.

2. Aggregate order counts per customer

Write a subquery to count total orders and canceled orders per customer. Use conditional aggregation (e.g., SUM(CASE WHEN canceled_at IS NOT NULL THEN 1 ELSE 0 END)) to get both counts in one pass.

3. Filter for customers with exactly two orders and two cancellations

Apply a HAVING clause to keep only customers where total_orders = 2 AND canceled_orders = 2. This ensures both orders were canceled.

4. Retrieve and order canceled timestamps

Join back to the orders table for these customers to get the canceled_at timestamps. Use ORDER BY customer_id, canceled_at ASC to return them in ascending order per customer.

5. Validate and format output

Check for duplicates, nulls, or unexpected results. Ensure the output includes customer_id and both canceled_at timestamps in ascending order, as requested.

Key Points to Mention

  • Use of conditional aggregation to count total and canceled orders in a single query.
  • Importance of filtering with HAVING after aggregation to ensure exactly two orders and two cancellations.
  • Handling of potential NULLs in canceled_at and ensuring they are treated as non-canceled.
  • Ordering of canceled_at timestamps ascending per customer, possibly using window functions or self-joins.
  • Consideration of data quality issues, such as duplicate orders or missing cancellation timestamps.
  • Clarifying business definitions: what counts as a 'lifetime order' and a 'canceled order' (e.g., canceled by customer vs. restaurant).

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q6

For each merchant in a given month, estimate the uplift in average order value when a promo is applied versus not. Output merchant ID, promo and non-promo order counts, both AOVs, and the difference. Then explain how you would compute a 95% confidence interval for that difference using either a SQL-based bootstrap or a Python snippet.

A/B Testing & ExperimentationProduct Analytics & Metrics
Author's notes

The SQL part is a straightforward GROUP BY with a CASE WHEN promo_id IS NOT NULL split.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, write a SQL query that aggregates orders by merchant and promo flag for the given month, computing counts and average order values, then join to get the difference. Next, explain how to compute a 95% confidence interval for the difference using either a SQL-based bootstrap (e.g., resampling with random numbers) or a Python snippet (e.g., using scipy or numpy).

Pro tip: Mention that you would check for sufficient sample size and consider using a t-test or bootstrap due to potential non-normality of order values. Also, note that you might need to handle merchants with zero promo or non-promo orders.

1. Clarify requirements and assumptions

Confirm the definition of 'promo' (e.g., any discount applied) and the month, and assume order-level data with merchant_id, order_value, promo_flag, and order_date.

2. Write SQL for aggregation

Use a query to group by merchant_id and promo_flag, filtering for the month, and compute COUNT(*) and AVG(order_value). Then pivot or self-join to get promo and non-promo counts and AOVs side by side.

3. Compute difference and handle edge cases

Calculate the difference in AOVs (promo AOV - non-promo AOV). Exclude or flag merchants with zero orders in either group to avoid division by zero or unreliable estimates.

4. Explain confidence interval via bootstrap

Describe resampling orders within each merchant and promo group with replacement, computing the difference in AOVs for each resample, and taking the 2.5th and 97.5th percentiles as the 95% CI. Mention implementing in SQL using random() or in Python with numpy/scipy.

5. Discuss interpretation and limitations

Interpret the CI: if it excludes zero, the uplift is statistically significant. Note limitations like multiple testing, confounding, and the need for randomization for causal inference.

Key Points to Mention

  • Use of SQL aggregation functions (COUNT, AVG) with GROUP BY and conditional aggregation (CASE WHEN) to pivot promo vs non-promo.
  • Handling merchants with zero orders in one group (e.g., exclude or use NULL).
  • Bootstrap method: resampling with replacement, computing difference in means, and deriving percentiles.
  • Implementation details: SQL random() for resampling or Python libraries like numpy.random.choice and scipy.stats.bootstrap.
  • Assumption of independence and identically distributed (i.i.d.) orders within each group for bootstrap validity.
  • Caveat about observational data: promo assignment may not be random, so difference may not be causal; suggest A/B test for causal uplift.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.