← Meta Interview Insights

Meta·Data Scientist·Technical Phone Screen·Senior

Senior
May 2026

Summary

SQL-heavy technical screen for a Data Scientist role at Meta. Three sub-parts all built on the same two-table schema, escalating from aggregation logic to percentage calculations to index design. Felt more like a take-home graded in real time than a conversation.

Questions Asked (3)

Q1

Given an interactions table and a products table, write SQL to return the count of products where the number of distinct buyers across all history is greater than 3 AND the total interaction count summed across all rows is greater than 10. Explain why you use HAVING instead of WHERE for these thresholds.

Product Analytics & MetricsData Modeling
Author's notes

The DISTINCT buyer part is where people slip up.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the table schemas and the definition of 'buyer' and 'interaction'. Then write a query that groups interactions by product, computes COUNT(DISTINCT buyer_id) and COUNT(*) per product, filters with HAVING on both conditions, and finally counts the resulting products. Explain that HAVING is used because the thresholds apply to aggregated values, not individual rows.

Pro tip: Mention that COUNT(DISTINCT buyer_id) can be expensive on large datasets, so in a real Meta-scale scenario you might pre-aggregate or use approximate distinct counts (e.g., HyperLogLog) if exactness isn't critical.

1. Clarify schema and definitions

Ask or state assumptions about the columns in the interactions and products tables, and define what constitutes a 'buyer' (e.g., user_id with a purchase event) and an 'interaction' (e.g., any row in the interactions table).

2. Aggregate per product

Write a subquery or CTE that groups the interactions table by product_id and computes COUNT(DISTINCT buyer_id) AS distinct_buyers and COUNT(*) AS total_interactions.

3. Apply HAVING filters

In the same aggregation query, add a HAVING clause with conditions distinct_buyers > 3 AND total_interactions > 10 to filter groups that meet both thresholds.

4. Count qualifying products

Wrap the filtered aggregation in an outer query that returns COUNT(*) AS product_count, or simply count the rows from the CTE.

5. Explain HAVING vs WHERE

Articulate that WHERE filters rows before grouping, while HAVING filters groups after aggregation; since the conditions depend on aggregate results, HAVING is required.

Key Points to Mention

  • HAVING operates on aggregated results, whereas WHERE operates on individual rows before grouping.
  • The query must use COUNT(DISTINCT buyer_id) to count distinct buyers, not just COUNT(buyer_id).
  • Both conditions must be satisfied simultaneously (AND logic).
  • The final output is a single count of products, not the list of products.
  • Performance considerations: indexing, pre-aggregation, or approximate distinct counts for large-scale data.
  • Assumptions about the schema (e.g., product_id in interactions, buyer_id column) should be stated clearly.

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

Q2

For US products only, compute the percentage of 'validate' interactions (by interaction_count) out of all interactions in the 7-day window ending on 2025-09-01. Use an INNER JOIN to filter to US products, explain why INNER JOIN is better than LEFT JOIN here, specify how you handle a zero denominator, and describe your rounding approach.

Product Analytics & MetricsTechnical Trade-offs
Author's notes

The zero denominator question is the part I almost glossed over.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Write a SQL query that filters interactions to the 7-day window ending 2025-09-01 and uses an INNER JOIN to restrict to US products, then compute the percentage of 'validate' interactions using a safe division that handles zero denominators. Explain that INNER JOIN is semantically correct because only US products should be included, and that it is more efficient than LEFT JOIN. Round the final percentage to two decimal places.

Pro tip: Mention that you would validate the denominator is non-zero before dividing, and that you would also check for edge cases like missing dates or product IDs. This shows you think about data quality, not just query syntax.

1. Define the time window and filter

Filter interactions to the 7-day window ending 2025-09-01, i.e., from 2025-08-26 to 2025-09-01 inclusive. Use a WHERE clause on the interaction date.

2. Join to US products with INNER JOIN

Use an INNER JOIN between the interactions table and the products table on product_id, with a condition that the product's country is 'US'. This ensures only US products are included.

3. Compute numerator and denominator

Calculate the total interaction_count for all interactions in the window (denominator) and the sum of interaction_count where interaction_type = 'validate' (numerator).

4. Handle zero denominator and round

Use a CASE statement or NULLIF to avoid division by zero, returning 0 or NULL as appropriate. Round the result to two decimal places using ROUND.

5. Explain join choice and edge cases

Justify INNER JOIN over LEFT JOIN: INNER JOIN is more efficient and semantically correct because we only want US products; LEFT JOIN would include non-US products with NULLs, requiring extra filtering. Mention handling of zero denominator and rounding.

Key Points to Mention

  • INNER JOIN is better than LEFT JOIN here because it filters out non-US products early, reducing the dataset and avoiding NULLs, which is both semantically correct and more performant.
  • Zero denominator handling: use NULLIF(denominator, 0) or a CASE statement to return 0 or NULL instead of causing a division error.
  • Rounding: use ROUND(percentage, 2) to present the result with two decimal places, and clarify whether the percentage is expressed as a fraction (0-1) or multiplied by 100.
  • Time window: explicitly state the inclusive date range (2025-08-26 to 2025-09-01) and ensure the date column is properly filtered.
  • Interaction count: sum the interaction_count column rather than counting rows, as the question specifies 'by interaction_count'.
  • Edge cases: consider products with no interactions in the window (they won't appear with INNER JOIN, which is correct) and ensure the denominator is not zero.

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

Q3

Write the complete SQL for both parts above, then specify which indexes you would add to each table to make these queries efficient. Also explain conceptually why HAVING is required for post-aggregation filters and WHERE cannot be used in that context.

Data ModelingTechnical Trade-offsSystem Design
Author's notes

Indexes part was straightforward: composite index on interactions(product_id, interaction_type, interaction_date) covers the filtering and grouping, and products(product_id, country) supports the join plus the country filter.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, restate the two queries to confirm understanding, then write clean SQL with explicit JOINs and aggregations. For indexing, propose composite indexes that cover the WHERE and GROUP BY columns, and explain that HAVING filters after aggregation while WHERE filters rows before grouping.

Pro tip: Mention that indexes should be designed based on query patterns, and that covering indexes can avoid table lookups. Also note that HAVING can sometimes be pushed down by the optimizer, but semantically it's post-aggregation.

1. Clarify the Queries

Restate the two parts to ensure you understand the required aggregations, filters, and joins. Ask clarifying questions if needed.

2. Write the SQL

Write the complete SQL for both queries, using proper JOINs, GROUP BY, and HAVING clauses. Ensure aliases and column references are correct.

3. Propose Indexes

For each table, suggest composite indexes on columns used in WHERE, JOIN, and GROUP BY. Explain how they improve performance.

4. Explain HAVING vs WHERE

Conceptually explain that WHERE filters rows before grouping, while HAVING filters groups after aggregation. Provide a simple example.

5. Summarize and Validate

Summarize your answer, and mention any trade-offs or alternative approaches, such as using subqueries or window functions.

Key Points to Mention

  • WHERE filters individual rows before GROUP BY; HAVING filters aggregated groups after GROUP BY.
  • Indexes should be composite and ordered to match query predicates (equality first, then range, then grouping).
  • Covering indexes can include all columns needed by the query to avoid table lookups.
  • Aggregate functions like COUNT, SUM, AVG cannot be used in WHERE.
  • Query optimization: sometimes HAVING can be rewritten as a subquery with WHERE for better performance.
  • Consider cardinality and selectivity when designing indexes.

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