← Meta Interview Insights

Meta·Data Scientist·Technical Phone Screen·Senior

Senior
Jul 2026

Summary

SQL-heavy technical screen for a Data Scientist role at Meta. Three questions, all SQL, progressively nastier. The last one about growth proportion had enough edge cases to make me second-guess my own logic twice.

Questions Asked (3)

Q1

Write a query to compute daily revenue broken out by creation source, ordered by date and creation source. Only include dates that actually appear in the ads table.

Product Analytics & MetricsData Modeling
Author's notes

Straightforward group-by aggregation.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by identifying the relevant tables and columns needed — likely an orders or transactions table joined or filtered against the ads table to restrict dates. Use GROUP BY on both date and creation_source, then aggregate revenue with SUM, ensuring the date filter is driven by an EXISTS or JOIN on the ads table. Finally, apply ORDER BY on date and creation_source to satisfy the output requirement.

Pro tip: Explicitly clarify what 'creation source' maps to in the schema before writing code — at Meta this could be a column like `created_source` or an enum; naming it correctly signals you understand the data model, and using a JOIN rather than a subquery on the ads date filter is often more performant and readable at scale.

1. Clarify the Schema

Identify the tables involved — typically an orders/revenue table with columns like order_date, creation_source, and revenue, plus an ads table that contains the valid dates. Confirm column names and data types before writing any SQL.

2. Filter Dates Using the Ads Table

Use an INNER JOIN or WHERE EXISTS clause to restrict the result set to only dates that appear in the ads table, ensuring no revenue rows from dates absent in ads are included.

3. Aggregate Revenue by Date and Source

Apply GROUP BY on the date column and creation_source column, then use SUM(revenue) to compute total daily revenue for each combination.

4. Apply Correct Ordering

Add ORDER BY date ASC, creation_source ASC at the end of the query to satisfy the requirement of ordering by date first, then creation source alphabetically.

5. Validate and Optimize

Review the query for edge cases such as NULL values in creation_source or revenue, and consider whether a DATE_TRUNC is needed if the timestamp is more granular than a day. Mention indexing on date and creation_source for production performance.

Key Points to Mention

  • Using INNER JOIN on the ads table (vs. a subquery) to enforce the date filter and its performance implications
  • DATE_TRUNC or CAST to normalize timestamps to the day level if the raw column is a timestamp
  • GROUP BY on both date and creation_source to get the correct granularity
  • SUM(revenue) as the aggregation function and handling potential NULLs with COALESCE if needed
  • ORDER BY date, creation_source to meet the explicit ordering requirement
  • Clarifying schema assumptions upfront (table names, column names, revenue definition) to demonstrate analytical rigor

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

Q2

Find the 10 countries with the fewest distinct active advertisers over the last 30 days, where active means at least one ad with revenue greater than zero in that window. Countries with zero active advertisers should still appear in the results. Break ties alphabetically.

Data ModelingProduct Analytics & Metrics
Author's notes

The zero-count requirement is what makes this annoying.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by identifying the relevant tables (countries, advertisers, ads/revenue) and clarify the date window logic using a relative 30-day filter. Use a LEFT JOIN from a countries reference table to ensure countries with zero active advertisers still appear, then aggregate, rank, and apply tie-breaking alphabetically.

Pro tip: Explicitly calling out the need for a countries reference table (or CROSS JOIN seed) to surface zero-advertiser countries signals strong data modeling instinct — many candidates miss this edge case and only return countries that already appear in the ads table.

1. Clarify Schema & Assumptions

Identify the tables involved — typically a countries table, an advertisers table, and an ads/revenue table with timestamps. Confirm what 'last 30 days' means (e.g., CURRENT_DATE - 30 vs. a rolling window) and whether 'distinct active advertisers' means unique advertiser IDs.

2. Filter Active Advertisers

Write a subquery or CTE that filters the ads table to the last 30 days and revenue > 0, then selects distinct advertiser_id and country combinations to define 'active' advertisers per country.

3. Aggregate by Country with LEFT JOIN

LEFT JOIN the active advertiser CTE onto a full countries reference table so that countries with no active advertisers appear with a count of zero. Use COUNT(DISTINCT advertiser_id) — which naturally returns 0 for NULLs after a LEFT JOIN — to get the active advertiser count per country.

4. Rank and Apply Tie-Breaking

Order the results by active_advertiser_count ASC, then by country_name ASC to handle alphabetical tie-breaking. Use LIMIT 10 (or RANK/ROW_NUMBER if you need to handle ties at the boundary explicitly).

5. Validate & Communicate Edge Cases

Mention edge cases such as advertisers operating in multiple countries (counted separately per country), ads with NULL revenue (excluded by revenue > 0), and whether the 30-day window is inclusive of today. Briefly walk through expected output shape to confirm correctness.

Key Points to Mention

  • Use a countries reference table with LEFT JOIN to ensure zero-advertiser countries are included in results — not just an inner join on the ads table.
  • Apply the 30-day date filter using a reliable expression like `ad_date >= CURRENT_DATE - INTERVAL '30 days'` and confirm whether the boundary is inclusive.
  • Use COUNT(DISTINCT advertiser_id) rather than COUNT(*) to correctly count unique advertisers, not ad impressions or rows.
  • Handle tie-breaking explicitly in the ORDER BY clause with a secondary sort on country name alphabetically (ASC).
  • Consider using a CTE for readability and modularity — first isolate active advertisers, then aggregate, then rank.
  • Flag the boundary condition at rank 10: if multiple countries tie at the 10th position, discuss whether to use LIMIT 10 (arbitrary cut) or RANK() to include all tied countries.

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

Q3

For each creation source, compute the proportion of advertisers who grew their spend by at least 1000 between the first 8 months of 2024 and the same period in 2025. The denominator is all advertisers with any spend in either period for that source. Advertisers missing from one period should be treated as having zero spend for that period.

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

This one took me a minute.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by aggregating advertiser spend for each period (Jan–Aug 2024 and Jan–Aug 2025) grouped by creation source, using FULL OUTER JOIN or UNION-based logic to ensure advertisers present in only one period are retained with zero spend for the missing period. Then compute the spend delta per advertiser per source, flag those with a delta of at least 1000, and divide by the total distinct advertisers per source to get the proportion.

Pro tip: Explicitly handle the 'missing advertiser' edge case by using a FULL OUTER JOIN or COALESCE on a unioned list of advertiser-source pairs — interviewers at Meta specifically look for candidates who anticipate data completeness issues rather than silently dropping advertisers who appear in only one period.

1. Aggregate Spend Per Period

Write two CTEs (or subqueries) that each sum spend per advertiser and creation source, one filtered to Jan 1 – Aug 31 2024 and the other to Jan 1 – Aug 31 2025. This isolates the two comparison windows cleanly.

2. Union Advertiser-Source Universe

Build a complete universe of (advertiser_id, creation_source) pairs by taking the UNION (not UNION ALL) of both period CTEs, ensuring every advertiser that appears in either period is represented. This forms the denominator base.

3. Join Periods and Impute Zeros

LEFT JOIN the 2024 and 2025 spend CTEs onto the universe CTE, using COALESCE(spend, 0) for any advertiser missing from a given period. This correctly treats absent advertisers as having zero spend.

4. Compute Delta and Flag Growth

Calculate spend_2025 - spend_2024 for each advertiser-source pair and create a binary flag (1 if delta >= 1000, else 0). This separates the numerator logic from the aggregation step.

5. Aggregate Proportion by Creation Source

GROUP BY creation_source and compute AVG(growth_flag) — or equivalently SUM(growth_flag) / COUNT(*) — to get the proportion of qualifying advertisers per source. Order results for readability.

Key Points to Mention

  • FULL OUTER JOIN vs. UNION-based universe approach to handle advertisers missing from one period — and why UNION is often safer for multi-source scenarios
  • COALESCE(spend, 0) to impute zero spend for missing advertisers rather than NULL, which would distort the delta calculation
  • Denominator definition: all advertisers with any spend in either period for that source, not just those present in both periods
  • Date filtering precision: using >= '2024-01-01' AND < '2024-09-01' (or equivalent) to correctly capture exactly 8 months
  • Potential data quality checks: duplicate advertiser-source rows within a period that could inflate spend if not aggregated first
  • Interpreting the business result: discussing which creation sources show higher growth proportions and what that might signal about advertiser quality or onboarding effectiveness

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