← Meta Interview Insights

Meta·Data Scientist·Technical Phone Screen·Senior

Senior
Sep 2025Remote

Summary

SQL-heavy technical screen for a DS role at Meta. Four interconnected tasks all built on the same three-table schema, escalating from a basic aggregation to a comparative summary and a business interpretation layer. Pretty brutal if you're rusty on window functions.

Questions Asked (4)

Q1

Given a shops table and a listings table, write SQL to compute each shop's visibility rate (average of is_visible across its listings), returning only shops with at least 5 listings and ranking them by visibility rate descending, breaking ties by total listing count descending.

Product Analytics & MetricsData Modeling
Author's notes

Straightforward GROUP BY with a HAVING filter, but I almost forgot the tie-breaking on total listings.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the schema and assumptions (e.g., is_visible is 0/1, listings table has shop_id foreign key). Then write a SQL query that groups by shop_id, computes AVG(is_visible) and COUNT(*), filters with HAVING COUNT(*) >= 5, and orders by visibility rate DESC, total listings DESC. Finally, discuss potential edge cases and performance considerations.

Pro tip: Mention that using AVG(is_visible) directly works for 0/1 flags, but if is_visible is stored as a string or boolean, you may need to cast it. Also, consider using a window function or subquery to rank shops if you need to return additional shop details.

1. Clarify requirements and schema

Confirm the table structures, data types, and definitions (e.g., is_visible as 0/1, shop_id in listings). Ask if shops with zero listings should be included (they shouldn't due to the 5-listing filter).

2. Write the core aggregation query

Use GROUP BY shop_id to compute AVG(is_visible) AS visibility_rate and COUNT(*) AS total_listings. Apply HAVING COUNT(*) >= 5 to filter shops.

3. Add ordering and tie-breaking

Order the results by visibility_rate DESC, then by total_listings DESC to break ties. Optionally, include shop_id for deterministic ordering.

4. Consider performance and edge cases

Discuss indexing on shop_id, handling NULLs in is_visible (e.g., COALESCE or ignore), and whether to use a subquery or CTE for readability.

5. Validate and explain the query

Walk through the query logic, test with sample data if possible, and explain how it meets the requirements.

Key Points to Mention

  • Use of AVG() on a binary column to compute visibility rate.
  • HAVING clause to filter groups with at least 5 listings.
  • ORDER BY with multiple keys: visibility_rate DESC, total_listings DESC.
  • Handling of NULL values in is_visible (e.g., COALESCE or WHERE is_visible IS NOT NULL).
  • Potential need to join shops and listings tables if shop details are required.
  • Performance considerations: indexing on shop_id, avoiding unnecessary joins.

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

Q2

Define 'new shop' as created within the last 30 days and compute an activity score per shop over a specific date window using weighted event type counts from a shop_events table. Write SQL returning one row per shop with shop_id, is_new flag, visibility_rate (NULL if fewer than 1 listing), and activity_score (0 if no events).

Product Analytics & MetricsData ModelingTechnical Trade-offs
Author's notes

This is where it got messy for me.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the schema and definitions: confirm the shop_events table columns (shop_id, event_type, event_timestamp), the shops table with creation date, and the exact date window for activity. Then outline a SQL query that aggregates events per shop, computes weighted counts, and joins with shop metadata to derive is_new, visibility_rate, and activity_score, handling edge cases with NULLIF and COALESCE.

Pro tip: Explicitly state your assumptions about the date window and event weights, and mention that you would validate the query with sample data or edge cases (e.g., shops with no events or listings) to ensure correctness before scaling.

1. Clarify requirements and schema

Ask about the exact date window, event types and their weights, and the definition of visibility_rate (e.g., listings per shop). Confirm table structures and join keys.

2. Compute activity score per shop

Aggregate shop_events within the date window, applying weights to each event type, and sum to get activity_score. Use a LEFT JOIN from shops to ensure all shops are included, with COALESCE to default to 0.

3. Derive is_new and visibility_rate

Calculate is_new by comparing shop creation date to current date (or reference date) within 30 days. Compute visibility_rate as listings count divided by something (e.g., total possible listings), using NULLIF to avoid division by zero and return NULL if fewer than 1 listing.

4. Combine and handle edge cases

Join the aggregated activity data with shop metadata, ensuring one row per shop. Use COALESCE for activity_score and CASE for visibility_rate to handle NULLs appropriately.

5. Validate and optimize

Test with edge cases (new shops, no events, no listings) and consider indexing on shop_id and event_timestamp for performance. Explain any trade-offs in the query design.

Key Points to Mention

  • Use of LEFT JOIN to include all shops, even those without events or listings
  • COALESCE to default activity_score to 0 when no events
  • NULLIF to handle division by zero for visibility_rate, returning NULL if fewer than 1 listing
  • Date filtering with a specific window (e.g., WHERE event_timestamp BETWEEN ...)
  • Weighted sum for activity_score using CASE statements or a mapping table
  • Definition of 'new shop' based on creation date within last 30 days relative to a reference date

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

Q3

Using the per-shop output from the previous query as a base, produce a 3-row summary table comparing new shops vs existing shops across mean activity score, median activity score (using an analytic function), and share of active shops (fraction with activity score above zero).

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

Median via analytic functions is always a bit awkward in SQL.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by building a CTE that computes per-shop metrics (mean, median via analytic function, and active flag) from the previous query's output. Then aggregate these metrics at the shop type level (new vs existing) using conditional aggregation, ensuring the median is correctly computed with an analytic function before grouping. Finally, format the result as a 3-row summary table (new, existing, overall) with the required columns.

Pro tip: When using an analytic function for median, compute it at the shop level first, then aggregate—avoid trying to compute median of medians. Also, explicitly handle ties and nulls in activity scores to ensure accurate active shop counts.

1. Define per-shop metrics

Create a CTE that calculates each shop's mean activity score, median activity score using an analytic function (e.g., PERCENTILE_CONT or MEDIAN), and a flag indicating if the shop is active (activity score > 0).

2. Classify shops as new or existing

Add a column that labels each shop as 'new' or 'existing' based on the business definition (e.g., shop creation date within a recent period).

3. Aggregate at shop type level

Group by the shop type label and compute the average of the per-shop means, the average of the per-shop medians, and the fraction of active shops (sum of active flags divided by count).

4. Include overall summary row

Use UNION ALL to add a third row that aggregates across all shops (without grouping by shop type) to provide an overall comparison.

5. Format and validate output

Ensure the final table has three rows (new, existing, overall) and the required columns, and validate that the median calculation is correct by checking a few shops manually.

Key Points to Mention

  • Use of analytic functions (e.g., PERCENTILE_CONT, MEDIAN) for median calculation at the shop level before aggregation.
  • Conditional aggregation (CASE WHEN) to compute the share of active shops.
  • Handling of NULL or zero activity scores when defining 'active'.
  • Importance of computing median at the correct granularity to avoid Simpson's paradox.
  • Use of UNION ALL to include an overall summary row for comparison.
  • Ensuring the final output is a 3-row table with clear labels for new, existing, and overall.

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

Q4

From the same dataset, identify the top 5 new shops by activity score where visibility rate is below 0.5, to surface shops that are active but underexposed. Also explain your assumptions around NULL vs 0 and how you'd guard against survivorship bias in this analysis.

Product Analytics & MetricsRoot Cause AnalysisTechnical Trade-offs
Author's notes

The SQL itself is a simple filter and ORDER BY, the interesting part is the conceptual question at the end.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the definitions of 'new shops', 'activity score', and 'visibility rate', then outline the SQL query with appropriate filters and ordering. Explicitly discuss how you handle NULLs versus zeros and how you would mitigate survivorship bias by considering shops that may have been removed or never appeared.

Pro tip: Mention that you would validate the results by checking the distribution of activity scores and visibility rates, and consider segmenting by shop category or region to ensure the insights are actionable.

1. Clarify definitions and assumptions

Define what 'new shop' means (e.g., created within last 30 days), how 'activity score' is calculated, and what 'visibility rate' represents (e.g., impressions per user or per session). Confirm whether NULLs should be treated as 0 or excluded.

2. Write the SQL query

Construct a query that filters for new shops, visibility rate < 0.5, orders by activity score descending, and limits to top 5. Use COALESCE or CASE to handle NULLs appropriately.

3. Address NULL vs 0

Explain that NULL indicates missing data, while 0 indicates a true zero value. For visibility rate, if the denominator is zero, the rate is undefined; decide whether to exclude or set to 0 based on business context.

4. Guard against survivorship bias

Consider shops that may have been deleted or never appeared in the dataset. Use left joins to include all shops, and analyze historical data to see if underexposed shops later became successful.

5. Validate and interpret results

Check for outliers, ensure the top 5 are truly underexposed, and provide recommendations for surfacing these shops (e.g., boosting visibility in recommendations).

Key Points to Mention

  • Definition of 'new shop' and time window (e.g., last 30 days)
  • Calculation of activity score and visibility rate
  • Handling NULLs: COALESCE vs filtering, and implications
  • Survivorship bias: including all shops, not just those currently active
  • SQL techniques: window functions, subqueries, or CTEs for clarity
  • Business impact: how to act on underexposed active shops

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