← Meta Interview Insights

Meta·Data Scientist·Technical Phone Screen·Senior

SeniorPrefer not to say
May 2026Remote

Summary

Meta DS interview with a meaty SQL case study involving two CSVs, schema design, and multi-step aggregation. The problem was technical enough that it felt more like a take-home than a phone screen, covering visit-level and visitor-level conversion logic with some genuinely tricky edge cases around booking attribution and deduplication.

Questions Asked (3)

Q1

Given two tables, visits and bookings, write SQL to produce a visit-level dataset where each row has a booked_flag indicating whether a booking occurred after that visit but before the next visit or 28 days later, whichever comes first. Make sure a single booking isn't counted across multiple visits for the same visitor.

A/B Testing & ExperimentationData ModelingProduct Analytics & Metrics
Author's notes

The dedup constraint is what makes this hard.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a window function to find the next visit date for each visitor, then join bookings to visits where the booking timestamp falls between the visit and the earlier of the next visit or 28 days later. To avoid double-counting a booking, assign each booking to the earliest qualifying visit using a row number partitioned by booking.

Pro tip: Explicitly discuss how you handle edge cases like multiple bookings within the same window or bookings that occur after the 28-day cutoff, and mention that you would validate the logic with a small test dataset.

1. Identify visit windows

Use LEAD() to get the next visit date for each visitor, then compute the window end as LEAST(next_visit_date, visit_date + INTERVAL '28 days').

2. Join bookings to visits

Join the visits table to the bookings table on visitor_id where booking_date > visit_date AND booking_date <= window_end.

3. Deduplicate bookings

Use ROW_NUMBER() partitioned by booking_id ordered by visit_date to assign each booking to the earliest qualifying visit, then filter to only the first occurrence.

4. Aggregate to visit level

Group by visit_id and set booked_flag = 1 if any booking was assigned to that visit, else 0.

5. Validate and handle edge cases

Check for overlapping windows, bookings exactly at boundaries, and ensure no booking is counted multiple times; consider using a temporary table or CTE for clarity.

Key Points to Mention

  • Use of window functions (LEAD, ROW_NUMBER) to handle sequential visits and deduplication.
  • Definition of the window: from visit date to the earlier of next visit or 28 days later.
  • Avoiding double-counting by assigning each booking to the earliest qualifying visit.
  • Handling visitors with only one visit (next visit is NULL, so window ends at 28 days).
  • Potential performance considerations and indexing on visitor_id and dates.
  • Validation with edge cases like bookings on the boundary or multiple bookings in one window.

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

Q2

Now produce a visitor-level dataset with one row per visitor, using their first visit timestamp and assignment. Set booked_flag_28d to 1 if any booking falls within 28 days of that first visit. If a visitor has conflicting assignment values across visits, use the one from the earliest visit.

Data ModelingProduct Analytics & MetricsA/B Testing & Experimentation
Author's notes

Collapsing to visitor-level felt more straightforward after the visit-level problem, but the conflicting assign edge case is sneaky.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by aggregating the visit-level data to the visitor level, using MIN(visit_timestamp) to identify the first visit and selecting the assignment from that earliest visit. Then left join to the booking data and use a conditional aggregation (e.g., MAX(CASE WHEN booking_date BETWEEN first_visit AND first_visit + INTERVAL '28 days' THEN 1 ELSE 0 END)) to create booked_flag_28d. Ensure the final output has exactly one row per visitor with the correct first visit timestamp and assignment.

Pro tip: When handling conflicting assignments, explicitly state that you're using the assignment from the earliest visit (e.g., via a window function or correlated subquery) and mention that this avoids double-counting visitors and maintains experiment integrity. Also, clarify how you handle ties in visit timestamps (e.g., by using a deterministic tiebreaker like visit_id).

1. Identify first visit per visitor

Use a GROUP BY visitor_id with MIN(visit_timestamp) to get the first visit timestamp for each visitor. Alternatively, use a window function like ROW_NUMBER() OVER (PARTITION BY visitor_id ORDER BY visit_timestamp) to rank visits and filter for the first.

2. Extract assignment from first visit

Join back to the original visit data on visitor_id and first visit timestamp to retrieve the assignment value from that earliest visit. If multiple visits share the same timestamp, apply a deterministic tiebreaker (e.g., lowest visit_id) to pick one assignment.

3. Join with booking data

Left join the visitor-level first visit data to the booking table on visitor_id. Ensure the join preserves all visitors, even those with no bookings.

4. Compute booked_flag_28d

For each visitor, check if any booking date falls within the 28-day window starting from the first visit timestamp. Use a conditional aggregation: MAX(CASE WHEN booking_date >= first_visit AND booking_date < first_visit + INTERVAL '28 days' THEN 1 ELSE 0 END) AS booked_flag_28d.

5. Finalize visitor-level dataset

Select visitor_id, first_visit_timestamp, assignment, and booked_flag_28d. Ensure the result has one row per visitor and validate that the flag is correctly computed (e.g., by checking edge cases like bookings exactly on day 28).

Key Points to Mention

  • Use of MIN(visit_timestamp) or ROW_NUMBER() to identify the first visit per visitor.
  • Handling conflicting assignments by taking the assignment from the earliest visit, possibly with a tiebreaker.
  • Left join to bookings to retain visitors with no bookings.
  • Conditional aggregation (e.g., MAX(CASE WHEN ...)) to create the binary booked_flag_28d.
  • Definition of the 28-day window: inclusive of start date, exclusive of end date (or clarify).
  • Importance of one row per visitor and avoiding duplicates.

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

Q3

For both datasets, aggregate conversion metrics by assignment group and country: total visits or visitors, number of bookers, and conversion rate. Be explicit about how you handle duplicates and timezone assumptions.

Product Analytics & MetricsA/B Testing & ExperimentationTechnical Trade-offs
Author's notes

The aggregation itself is just GROUP BY assign, country with a SUM and division.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the data schema and definitions (e.g., what constitutes a visit, a booker, and how duplicates arise). Then outline a SQL/pandas aggregation plan that deduplicates at the appropriate grain (e.g., user-session or user-day) and handles timezone conversion consistently before grouping by assignment group and country. Finally, compute the metrics and discuss validation checks and edge cases.

Pro tip: Explicitly state your timezone assumption (e.g., UTC or user-local) and justify it based on business context; also mention that you would check for duplicate user IDs across assignment groups and decide on a deterministic rule (e.g., first exposure) to avoid double-counting.

1. Clarify definitions and data grain

Confirm what a 'visit' means (page view, session, unique visitor) and what a 'booker' is (user who completed a booking). Identify the grain of the raw data (e.g., event-level) and potential duplicate sources.

2. Handle duplicates and timezone

Decide on deduplication logic (e.g., keep first event per user per day) and apply a consistent timezone conversion (e.g., convert all timestamps to UTC or the user's local timezone) before aggregation.

3. Aggregate metrics by group and country

Write an aggregation query (SQL or pandas) that groups by assignment group and country, counting distinct visitors/bookers and computing conversion rate as bookers divided by visitors.

4. Validate and sanity-check results

Check for anomalies such as conversion rates >100%, missing countries, or unexpected group sizes. Compare totals against known benchmarks or a quick manual calculation.

5. Communicate assumptions and limitations

Summarize the key assumptions (e.g., timezone, dedup rule) and note any limitations (e.g., users switching groups) that could affect interpretation.

Key Points to Mention

  • Definition of conversion rate: number of bookers divided by number of visitors (or visits), and whether to use unique visitors or sessions.
  • Deduplication strategy: e.g., deduplicate on user_id + date to avoid counting multiple visits per day, or use session_id if visits are sessions.
  • Timezone handling: convert all timestamps to a single timezone (e.g., UTC) or to user-local timezone, and ensure consistency across datasets.
  • Handling users in multiple assignment groups: decide on a rule (e.g., first assignment, last assignment, or exclude) and document it.
  • Edge cases: missing country data, null values, and how to treat them (e.g., exclude or bucket as 'Unknown').
  • Validation: cross-check totals with raw counts, ensure conversion rate is between 0 and 1, and check for statistical significance if comparing groups.

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