← DoorDash Interview Insights

DoorDash·Data Scientist·Take-home Assignment·Senior

Senior
May 2026Remote

Summary

DoorDash data science take-home, heavy SQL focus with BigQuery/Snowflake syntax. Four tasks all in one script, all requiring CTEs, and they really wanted to see LAG and QUALIFY used correctly. Not a casual exercise.

Questions Asked (4)

Q1

Using CTEs and window functions, compute the city-day cold complaint rate for completed deliveries over the last 30 days. Return city, date, delivery count, cold complaint count, and complaint rate. Handle timezone conversion from UTC to city-local time and state your assumption.

Product Analytics & MetricsData Modeling
Author's notes

The timezone part is what trips people up.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining the metric and assumptions, then build a SQL query using CTEs to filter completed deliveries in the last 30 days, convert UTC timestamps to city-local time, and aggregate counts by city and date. Use window functions to compute the complaint rate as a percentage, ensuring proper handling of time zones and date boundaries.

Pro tip: Always state your timezone assumption explicitly (e.g., using the delivery's city timezone) and consider that 'last 30 days' should be relative to the current date in each city's local timezone to avoid off-by-one errors.

1. Clarify metric and assumptions

Define 'cold complaint rate' as the number of cold complaints divided by completed deliveries, and state that you will convert UTC timestamps to city-local time using the city's timezone.

2. Filter and prepare data

Use a CTE to select completed deliveries from the last 30 days, converting the delivery timestamp from UTC to the city's local timezone.

3. Aggregate counts by city and date

In another CTE, group by city and local date, counting total deliveries and cold complaints (e.g., using a CASE statement or filtering on complaint type).

4. Compute complaint rate with window functions

Use a window function (e.g., SUM OVER) to calculate the complaint rate as cold complaints divided by deliveries, or simply compute the ratio directly.

5. Final selection and ordering

Select city, date, delivery count, cold complaint count, and complaint rate, ordering by city and date for readability.

Key Points to Mention

  • Timezone conversion: use city-local timezone (e.g., via AT TIME ZONE) and state the assumption.
  • Definition of 'last 30 days': relative to current date in each city's local timezone.
  • Filter for completed deliveries only (e.g., status = 'completed').
  • Identify cold complaints (e.g., complaint_type = 'cold' or similar).
  • Use CTEs for readability and window functions for rate calculation.
  • Handle potential NULLs or division by zero in complaint rate.

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

Q2

Using LAG over order_events partitioned by order_id, compute ready-to-pickup and pickup-to-dropoff durations per order. Then compare median pickup-to-dropoff time between orders with a cold complaint versus without, broken out by city, for a one-month window. Use QUALIFY to keep only cities where the difference exceeds 12 minutes.

Product Analytics & MetricsA/B Testing & Experimentation
Author's notes

LAG usage was fine but the QUALIFY filter on the city-level difference is a bit awkward because you're qualifying on an aggregated value, not a row-level window.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, use LAG to compute the time differences between consecutive order events (ready-to-pickup and pickup-to-dropoff) per order. Then, aggregate median pickup-to-dropoff times by city and cold complaint status, and use QUALIFY to filter cities where the difference exceeds 12 minutes. Focus on a one-month window and ensure proper partitioning and ordering.

Pro tip: When using LAG, ensure the window is ordered by event timestamp and partitioned by order_id to avoid mixing events from different orders. Also, consider using APPROX_PERCENTILE for median to handle large datasets efficiently.

1. Compute event durations

Use LAG over order_events partitioned by order_id and ordered by event timestamp to calculate ready-to-pickup and pickup-to-dropoff durations for each order.

2. Filter and label orders

Restrict to a one-month window and join with complaint data to label each order as having a cold complaint or not.

3. Aggregate medians by city and complaint status

Group by city and cold complaint flag, and compute the median pickup-to-dropoff duration for each group.

4. Compare and filter cities

Calculate the difference in median pickup-to-dropoff time between orders with and without cold complaints per city, then use QUALIFY to keep only cities where the difference exceeds 12 minutes.

Key Points to Mention

  • Use of LAG with proper partitioning and ordering to compute durations
  • Handling of timestamps and ensuring correct event sequence
  • Definition and calculation of median (e.g., using PERCENTILE_CONT or APPROX_PERCENTILE)
  • Joining with complaint data and defining cold complaint flag
  • Applying QUALIFY to filter cities based on the difference threshold
  • Importance of time window filtering (one month) and potential data quality checks

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

Q3

For each courier, restrict to their last 100 completed deliveries in their city up to a cutoff date. Flag couriers whose cold complaint rate exceeds twice the city median rate and who have at least 100 deliveries. Use QUALIFY both to select the last 100 deliveries per courier and to filter the outlier couriers.

Data ModelingRoot Cause Analysis
Author's notes

Two separate QUALIFY uses in one task.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, use a QUALIFY clause with ROW_NUMBER() to select the last 100 completed deliveries per courier in each city up to the cutoff date. Then, compute the cold complaint rate per courier and the city median rate, and finally use another QUALIFY clause to flag couriers whose rate exceeds twice the city median and who have at least 100 deliveries.

Pro tip: When using QUALIFY for the last 100 deliveries, ensure the window function partitions by courier and city and orders by delivery timestamp descending. For the outlier filter, use a window function to compute the city median rate, and remember that QUALIFY can reference window functions directly, avoiding subqueries.

1. Filter and rank deliveries

Filter deliveries to completed status and delivery date <= cutoff. Use ROW_NUMBER() OVER (PARTITION BY courier_id, city ORDER BY delivery_timestamp DESC) to rank each courier's deliveries.

2. Select last 100 deliveries

Apply QUALIFY row_number <= 100 to restrict to the last 100 deliveries per courier in their city.

3. Compute courier and city metrics

Calculate each courier's cold complaint rate (cold complaints / total deliveries) and the city median rate using PERCENTILE_CONT or MEDIAN window function.

4. Flag outlier couriers

Use QUALIFY to filter couriers where courier_rate > 2 * city_median_rate AND total_deliveries >= 100.

Key Points to Mention

  • Use of QUALIFY to simplify window function filtering without subqueries
  • Partitioning by both courier and city to handle couriers in multiple cities
  • Ordering by delivery timestamp descending to get the most recent deliveries
  • Computing city median rate using window functions like PERCENTILE_CONT or MEDIAN
  • Ensuring the 100-delivery threshold is applied after selecting the last 100 deliveries
  • Handling ties in delivery timestamps with additional ordering criteria if needed

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

Q4

Compute the P90 of pickup-to-dropoff time per city. For each courier, find the share of their deliveries that exceed their city's P90. Use QUALIFY to return the top 5 couriers per city by that share, with ties broken by higher delivery count. Explain the tie-breaking window you used.

Product Analytics & MetricsTechnical Trade-offs
Author's notes

P90 with PERCENTILE_CONT is straightforward.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, compute the P90 of pickup-to-dropoff time for each city using a window function or aggregation. Then, for each courier, calculate the share of their deliveries that exceed their city's P90. Finally, use QUALIFY with a window function that orders by share descending and delivery count descending to select the top 5 couriers per city, explaining that the tie-breaker is applied within the same window ordering.

Pro tip: When using QUALIFY with ROW_NUMBER(), ensure the window's PARTITION BY city and ORDER BY includes both the share and delivery count to handle ties deterministically. Also, consider whether the P90 should be computed over all deliveries or only those from couriers with a minimum number of deliveries to avoid noise.

1. Compute city-level P90

Calculate the 90th percentile of pickup-to-dropoff time for each city using an aggregate function like PERCENTILE_CONT(0.9) or APPROX_QUANTILES, grouped by city.

2. Flag deliveries exceeding P90

Join the city-level P90 back to the deliveries table and create a binary flag indicating whether each delivery's pickup-to-dropoff time exceeds the city's P90.

3. Calculate courier share

For each courier and city, compute the share of deliveries that exceed the P90 (i.e., average of the flag) and the total delivery count.

4. Rank couriers with QUALIFY

Use QUALIFY with ROW_NUMBER() OVER (PARTITION BY city ORDER BY share DESC, delivery_count DESC) to assign ranks, then filter for rank <= 5.

5. Explain tie-breaking window

Describe that the window orders by share descending first, then by delivery count descending to break ties, ensuring deterministic selection.

Key Points to Mention

  • Use of PERCENTILE_CONT or APPROX_QUANTILES for P90 calculation, noting trade-offs between exact and approximate percentiles.
  • Handling of ties: the window function's ORDER BY clause includes both share and delivery count to break ties.
  • QUALIFY clause to filter the ranked results without a subquery, improving readability.
  • Consideration of minimum delivery threshold per courier to avoid unreliable shares from small sample sizes.
  • Potential need to handle cities with few deliveries where P90 might be unstable.
  • Explanation that the tie-breaking window is the same window used for ranking, ensuring consistency.

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