LIMITED TIME 🎁: Register now to get 60 minutes of AI Mock Interviewing for FREE!

Join
    Microsoft Interview Insights
    Microsoft logo
    Microsoft·Data Scientist·Technical Phone Screen·Senior
    Senior
    Jul 2026
    3

    Summary

    Microsoft data scientist technical screen, heavy SQL focus with some tricky edge cases built into the schema. Three-part question that escalated from a delivery rate calculation to a scenario-based switching analysis. Felt like a reasonable challenge but part (c) was a curveball I wasn't fully ready for.

    Questions Asked(3)

    Product Analytics & MetricsData Modeling
    A
    Author's notesFirst line only

    The spam_folder filter tripped me up first.

    Suggested Approach

    Start by clearly defining the data pipeline: filter the Emails table to the last 7 days, join to Deliveries while excluding spam_folder rows and selecting the earliest delivered event per email, then compute the 5-minute delivery flag. Finally, aggregate by provider and recipient domain to compute the proportion, explicitly handling NULLs from missing delivery records as undelivered (0).

    Pro tip: Explicitly call out the edge cases — bounces followed by a valid delivery, missing delivery records, and spam_folder exclusion — before writing any SQL; interviewers at Microsoft reward candidates who surface ambiguity and state assumptions rather than silently baking them in.
    1

    Scope & Filter the Emails Table

    Filter the Emails table to only rows where send_time falls within the last 7 days (e.g., send_time >= CURRENT_TIMESTAMP - INTERVAL '7 days'). Extract the provider and recipient domain from the email address fields at this stage to keep downstream logic clean.

    2

    Prepare the Deliveries Table

    Filter out any rows in the Deliveries table where event_type = 'spam_folder', then for each email_id select the earliest delivered event using MIN(event_time) WHERE event_type = 'delivered'. This correctly handles the bounce-then-deliver scenario by ignoring event ordering and focusing solely on the earliest delivered timestamp.

    3

    Join & Compute the 5-Minute Flag

    LEFT JOIN the filtered Emails table to the prepared Deliveries CTE on email_id, so emails with no delivery record produce a NULL delivery time. Compute a binary flag: 1 if (earliest_delivered_time - send_time) <= 5 minutes, else 0 (treating NULL as 0 via COALESCE or a CASE statement).

    4

    Aggregate by Provider and Recipient Domain

    GROUP BY provider and recipient_domain, then compute the proportion as SUM(delivered_within_5min_flag) / COUNT(*). Optionally include COUNT(*) as a volume column so stakeholders can assess statistical reliability of each group's proportion.

    5

    Validate & Communicate Assumptions

    State your assumptions explicitly: 'delivered' is the only qualifying event type, spam_folder rows are excluded before finding the earliest event, missing records are treated as undelivered, and the 5-minute window is inclusive. Mention that you'd validate row counts at each CTE stage to catch unexpected data issues.

    Key Points to Mention

    LEFT JOIN to preserve emails with no delivery record and treat them as undelivered (proportion denominator includes all sent emails)
    Use MIN(event_time) filtered to event_type = 'delivered' to correctly handle the bounce-then-deliver edge case without relying on row ordering
    Explicitly exclude spam_folder rows before computing the earliest delivered event, not after, to avoid spam events polluting the MIN calculation
    Use COALESCE or a CASE WHEN NULL THEN 0 pattern to convert missing delivery records into a 0 flag rather than dropping them from the aggregate
    Extract recipient domain via string parsing (e.g., SPLIT_PART(recipient_email, '@', 2)) and clarify whether 'provider' refers to the sending provider field or is derived from the sender domain
    Include a COUNT(*) or sample size column alongside the proportion to flag low-volume provider/domain combinations where the metric may be statistically unreliable
    Data ModelingRoot Cause Analysis
    A
    Author's notesFirst line only

    Straightforward once you've already built the CTEs from part (a).

    Suggested Approach

    Break the problem into sequential filtering steps: first identify message IDs where the earliest delivery event is a bounce, then among those find a subsequent 'delivered' event, and finally compute the lag between the original send time and that first delivered event. Use window functions to rank events per message and apply conditional filtering to enforce the ordering constraint. Express the solution in SQL with clear CTEs to keep logic readable and auditable.

    Pro tip: Explicitly define 'first observed delivery event' using ROW_NUMBER() or FIRST_VALUE() partitioned by message_id and ordered by event timestamp — interviewers at Microsoft often probe whether candidates handle ties or ambiguous ordering, so stating your tie-breaking assumption upfront signals analytical rigor.
    1

    Clarify Schema & Assumptions

    Identify the relevant tables (e.g., messages with send_time, events with message_id, event_type, event_timestamp). Confirm event_type values ('bounce', 'delivered') and whether a single message can have multiple events of the same type.

    2

    Rank Events Per Message

    Use ROW_NUMBER() or RANK() partitioned by message_id and ordered by event_timestamp to label each event chronologically. This lets you reliably identify the 'first' delivery-related event per message.

    3

    Filter Messages Where First Event Is a Bounce

    From the ranked events, keep only message IDs where the row ranked #1 has event_type = 'bounce'. This isolates the cohort of messages that initially bounced.

    4

    Find the First Subsequent 'Delivered' Event

    Within the filtered cohort, identify the earliest 'delivered' event that occurs after the bounce. Join back to the messages table to retrieve the original send_time for lag calculation.

    5

    Apply the 5-Minute Threshold & Compute Lag

    Filter to rows where the first delivered event timestamp minus the original send_time exceeds 5 minutes, then compute the lag in minutes using DATEDIFF or equivalent. Return message_id and the computed lag.

    Key Points to Mention

    Use of window functions (ROW_NUMBER/RANK) to determine event ordering per message_id rather than relying on unreliable insertion order
    Defining 'first observed delivery event' precisely and stating tie-breaking logic (e.g., by event_timestamp, then event_id as a tiebreaker)
    Separating the bounce-first filter from the delivered-event filter using CTEs for clarity and testability
    Using DATEDIFF or TIMESTAMPDIFF to compute the lag in minutes between send_time and the first delivered event timestamp
    Handling edge cases such as messages with a bounce but no subsequent delivered event (these should be excluded via INNER JOIN or EXISTS)
    Discussing indexing on (message_id, event_timestamp) as a performance consideration for large-scale event logs at Microsoft scale
    Product Analytics & MetricsA/B Testing & ExperimentationData Modeling
    A
    Author's notesFirst line only

    This one took me a minute to even parse.

    Suggested Approach

    Treat this as a cumulative window analysis problem where you compute a running delivered-within-5-minutes rate for each email provider (Gmail vs. Outlook) restricted to the ms.com recipient domain, updating the cumulative rate after each send date. Then scan chronologically for the first date where Outlook's cumulative rate strictly exceeds Gmail's cumulative rate, and surface that date along with both rates as the justification.

    Pro tip: Emphasize that 'cumulative up to and including each send date' means you must use a running sum of delivered and total sends — not a rolling window — so early-day noise is dampened over time; mentioning this distinction signals strong statistical intuition and prevents a common implementation mistake.
    1

    Filter and Scope the Data

    Restrict the dataset to rows where the recipient domain is ms.com and the send date falls within the specified 7-day window. Ensure you have columns for send date, email provider (Gmail vs. Outlook), whether the email was delivered within 5 minutes, and a total send count.

    2

    Aggregate Daily Counts per Provider

    Group by send date and provider to compute two daily metrics: the number of emails delivered within 5 minutes and the total emails sent. This gives you a clean daily summary table with one row per (date, provider) combination.

    3

    Compute Cumulative Running Rates

    For each provider, sort by send date and apply a cumulative sum over delivered counts and total counts separately, then divide to get the cumulative delivered-within-5-minutes rate at each date. Using cumulative sums (not averages of daily rates) correctly weights days with higher send volumes.

    4

    Identify the Crossover Date

    Join the two cumulative rate series on send date and scan chronologically for the earliest date where Outlook's cumulative rate is strictly greater than Gmail's cumulative rate. This is the candidate switch date.

    5

    Output and Validate the Result

    Return the identified date along with both cumulative rates (e.g., Outlook: 94.2%, Gmail: 91.8%) as the justification. Sanity-check by confirming no earlier date satisfies the strict inequality and that sample sizes on that date are large enough to be meaningful.

    Key Points to Mention

    Cumulative rate = running sum of delivered / running sum of total sends (not an average of daily rates), which correctly handles volume-weighted days
    The 'strictly improved' condition means Outlook rate must be > Gmail rate, not >= , so ties do not qualify as a switch point
    Domain filtering to ms.com is critical — deliverability patterns differ by recipient domain and mixing domains would confound the analysis
    Mention potential data sparsity risk: if one provider has very few sends on early dates, the cumulative rate may be volatile and the crossover could be a statistical artifact rather than a true signal
    Consider flagging the sample size (total cumulative sends per provider) alongside the rates to give stakeholders confidence in the conclusion
    In a real business context, note that a single metric crossover may not be sufficient justification alone — you'd want to check for confounders like send volume changes, day-of-week effects, or concurrent infrastructure changes

    Discussion(3)

    Sign in to join the discussion.

    T
    TheCareerCo· 57d ago
    Q3For the ms.com domain over the same 7-day window, find the earliest calendar date where switching from Gmail to Outlook would have strictly improved deliverability. Base this on cumulative delivered-within-5-minutes rates up to and including each send date. Output the date and the cumulative rates that justify the switch.

    The cumulative framing is what makes this genuinely hard to parse on first read. A per-day snapshot would be simple aggregation, but cumulative rates mean your denominator and numerator for any given date both include everything from the start of the 7-day window through that date. So you're not asking 'which provider was better today' but 'if I had committed to a provider from day one through today, which would have served me better cumulatively.'

    The cleanest approach I can think of: build a base table at the send-date grain that flags each email as delivered-within-5-min or not (using the same logic from part a, scoped to ms.com recipients). Then for each calendar date in the window, compute a running SUM of delivered flags and a running COUNT of total sends, partitioned by provider, ordered by send date with ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. That gives you cumulative numerator and denominator per provider per date, so the rate is just their ratio.

    Then you pivot or self-join to get Gmail and Outlook side by side on the same date row, filter to rows where Outlook's cumulative rate strictly exceeds Gmail's, and take the MIN(send_date). The 'strictly improves' wording matters, equal rates don't qualify.

    Second-guessing the ROWS BETWEEN framing out loud is actually not the worst thing in a Microsoft phone screen. I've found that thinking out loud about window frame semantics, even if you stumble a bit, lands better than silently writing something that turns out to be wrong. The interviewers at that level generally care more about whether you understand what the frame is doing than whether you memorized the exact syntax.

    DJ
    David J. Aris· 57d ago
    Q1Given an Emails table and a Deliveries table, compute the proportion of emails delivered within 5 minutes of send time, grouped by provider and recipient domain, for emails sent in the last 7 days. Use the earliest delivered event, ignore spam_folder rows, and treat missing delivery records as undelivered. A bounce followed by a later delivery still counts if the delivered event falls within the 5-minute window.

    Your instinct about filtering spam_folder early is exactly right, and it's the kind of thing that's easy to miss under pressure. The way I think about it: if you let spam_folder rows survive into your MIN(event_ts) calculation, you might pull a timestamp from a spam event that technically precedes the real delivered event, which completely breaks the 5-minute window check. The filter has to live inside the CTE that isolates delivered rows, not outside it.

    The bounce-then-deliver rule is the other landmine. A lot of people read that and write something like MIN(event_ts) across all statuses, which grabs the bounce timestamp instead of the delivered one. You need to be surgical: filter to status = 'delivered', then MIN(event_ts), then join back to Emails on message_id and check whether that minimum delivered timestamp falls within send_time + 5 minutes. The bounce is irrelevant to the calculation, it just can't be allowed to pollute your event selection.

    For the grouping, make sure your denominator is total emails sent in the window, not total emails with any delivery record. Missing delivery records are undelivered, so you need a LEFT JOIN from Emails to your cleaned delivery CTE, and NULLs from the join count as failures. I've seen people accidentally inner join and quietly drop the undelivered population, which inflates the rate. Microsoft screens at this level tend to have at least one schema detail that punishes exactly that kind of shortcut.

    SM
    Sarah Millstone· 57d ago
    Q2Return all message IDs where the first observed delivery event was a bounce and a subsequent delivered event happened more than 5 minutes after the original send time. Include the lag in minutes between send time and the first delivered event.

    ROW_NUMBER() partitioned by message_id ordered by event_ts is the right call. Quick note though: if your Deliveries table can have ties on event_ts for the same message_id, ROW_NUMBER() will arbitrarily pick one, and that could matter if one tie is a bounce and the other isn't. Worth a one-sentence callout to the interviewer just to show you're thinking about it, even if they wave it off.

    Interview Details

    CompanyMicrosoft
    RoleData Scientist
    RoundTechnical Phone Screen
    LevelSenior
    DateJul 2026

    Questions in this post

    Share your own experience

    Help the community by sharing what you went through.