← Meta Interview Insights

Meta·Data Scientist·Technical Phone Screen·Senior

Senior
Jun 2026

Summary

Meta DS technical screen, all SQL, no behavioral at all. Four questions built on the same schema and they kept layering complexity. I came out feeling like I'd been run over by a window function.

Questions Asked (4)

Q1

Given a schema with users, friendships, posts, and feed impressions, classify each impression as coming from a friend or an unconnected author relative to the viewer. Then write SQL to compute, for each (user_id, impression_date), the fraction of impressions that are friend-sourced vs unconnected.

Product Analytics & MetricsData Modeling
Author's notes

The join logic itself isn't hard but I kept second-guessing the direction.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the schema and define what constitutes a friend-sourced impression (viewer and author are friends) versus unconnected (no friendship). Then, write a SQL query that joins impressions with friendships to classify each impression, and finally aggregate by user and date to compute the fraction of friend-sourced impressions.

Pro tip: Remember that friendships are bidirectional; ensure your join condition captures both directions (user_id = friend_id OR friend_id = user_id) to avoid missing friendships. Also, consider using a LEFT JOIN to handle cases where there is no friendship, labeling those as unconnected.

1. Understand the schema and define friend relationship

Identify the relevant tables and columns: users, friendships (likely with user_id and friend_id), posts (with author_id), and impressions (with viewer_id, post_id, impression_date). Define a friend as a user who has a mutual friendship with the viewer.

2. Classify each impression

Join impressions with posts to get the author, then left join with friendships to check if the viewer and author are friends. Use a CASE statement to label each impression as 'friend' if a friendship exists, else 'unconnected'.

3. Aggregate by user and date

Group by viewer_id and impression_date, and compute the count of friend impressions and total impressions. Then calculate the fraction as friend_count / total_count.

4. Write the final SQL query

Combine the classification and aggregation into a single query, ensuring proper handling of NULLs and using appropriate aggregation functions.

Key Points to Mention

  • Bidirectional nature of friendships: ensure the join condition checks both (viewer_id = friend_id AND author_id = user_id) OR (viewer_id = user_id AND author_id = friend_id).
  • Use of LEFT JOIN to include impressions from unconnected authors and avoid filtering them out.
  • Handling of self-impressions: if a user sees their own post, it should be classified as unconnected (or excluded based on business rules).
  • Date handling: ensure impression_date is in the correct format and consider time zones if applicable.
  • Performance considerations: indexing on join keys and filtering before aggregation if possible.
  • Edge cases: users with no friends, posts with no impressions, and ensuring fractions are computed correctly when total impressions are zero.

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

Q2

Define a weighted social engagement score per viewer-day and content source (friend vs unconnected), using like=1, comment=3, share=5. Compute the score from interactions on that date, where impressions with no interactions contribute 0. Return one row per (user_id, date, content_source) with impression count, interaction breakdown by type, and weighted score.

Product Analytics & MetricsData Modeling
Author's notes

This one tripped me up more than I expected.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the grain: one row per (user_id, date, content_source). Then walk through the aggregation logic: join impressions to interactions, pivot interaction types into counts, apply weights, and sum to get the weighted score. Emphasize that impressions without interactions still appear with zero counts and zero score.

Pro tip: Mention that you would validate the output by checking that the sum of interaction counts never exceeds impression count and that the weighted score is zero when all interaction counts are zero. Also note that you would handle potential duplicate interactions by deduplicating on interaction_id if available.

1. Clarify the grain and definitions

Confirm that the output is one row per user_id, date, and content_source (friend vs unconnected). Define what constitutes an impression and an interaction, and ensure you understand how content_source is determined (e.g., from the impression or interaction metadata).

2. Aggregate impressions and interactions

From the impressions table, count distinct impressions per user-day-source. From the interactions table, count interactions by type (like, comment, share) per user-day-source. Use a left join from impressions to interactions to retain impression-only rows.

3. Compute weighted score

Apply weights: like=1, comment=3, share=5. Multiply each interaction count by its weight and sum to get the weighted social engagement score. Ensure that rows with no interactions have a score of 0.

4. Format the output

Select user_id, date, content_source, impression_count, like_count, comment_count, share_count, and weighted_score. Order by user_id, date, and content_source for readability.

5. Validate and handle edge cases

Check for negative or missing values, ensure interaction counts are non-negative integers, and verify that the weighted score is consistent with the counts. Consider how to handle multiple interactions of the same type by the same user on the same content (e.g., multiple likes) — typically count each interaction event.

Key Points to Mention

  • Grain: one row per (user_id, date, content_source) — emphasize the importance of defining the grain upfront.
  • Content source distinction: friend vs unconnected — explain how this is derived (e.g., from the impression's content source or the relationship between users).
  • Weighted score formula: 1*like_count + 3*comment_count + 5*share_count.
  • Impressions with no interactions: they should still appear with zero counts and zero score, so use a left join or union approach.
  • Handling multiple interactions: count each interaction event, not just distinct users, unless specified otherwise.
  • Data quality checks: ensure no duplicate interactions, handle nulls, and validate that interaction counts ≤ impression count.

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

Q3

For a specific date, return the top 2 posts per user by weighted engagement score using the same weights. Use dense_rank() to handle ties so all tied posts at the cutoff are included, with ties broken by post_id ascending.

Product Analytics & MetricsAlgorithms & Data Structures
Author's notes

Straightforward window function question.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, filter the posts to the specific date and compute the weighted engagement score for each post using the given weights. Then, use a window function with dense_rank() partitioned by user_id and ordered by weighted score descending, post_id ascending, to rank posts per user. Finally, select rows where the dense rank is <= 2, ensuring ties at the cutoff are included.

Pro tip: Clarify the tie-breaking logic: dense_rank() with ORDER BY weighted_score DESC, post_id ASC ensures deterministic ranking and includes all tied posts at the cutoff. Also, confirm whether the date filter should be applied before or after computing scores, as it affects performance.

1. Filter and compute scores

Filter the posts table to the specific date and calculate the weighted engagement score for each post using the provided weights.

2. Apply dense_rank()

Use a window function to assign a dense rank to each post within each user, ordering by weighted score descending and post_id ascending.

3. Select top 2 per user

Retrieve only the rows where the dense rank is less than or equal to 2, which includes all tied posts at the cutoff.

4. Validate and handle edge cases

Check for users with fewer than 2 posts, null scores, or missing weights, and ensure the result is deterministic.

Key Points to Mention

  • Use of dense_rank() to handle ties and include all tied posts at the cutoff.
  • Ordering by weighted_score DESC, post_id ASC for deterministic tie-breaking.
  • Partitioning by user_id to rank posts within each user.
  • Filtering by the specific date before or after score computation (consider performance).
  • Handling edge cases like users with fewer than 2 posts or null engagement metrics.
  • Ensuring the weighted score calculation uses the same weights as specified.

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

Q4

Compute month-over-month percent change in weighted engagement per content source between two consecutive months, aggregated across all users. Generate a month calendar CTE to handle missing months as zero before applying LAG. Explain your assumptions about multiple interactions on the same post and timezone boundaries.

Product Analytics & MetricsA/B Testing & ExperimentationData Modeling
Author's notes

The CTE calendar spine is the part I think most people skip and then wonder why their LAG returns NULL instead of a clean 0.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the metric definition and assumptions, then outline a SQL solution that uses a month calendar CTE to fill missing months with zero, computes weighted engagement per source per month, and applies LAG to calculate month-over-month percent change. Emphasize how you handle multiple interactions and timezone boundaries to ensure accurate aggregation.

Pro tip: Explicitly state that you would validate the calendar CTE against the date range of the data and confirm that zero-filling is appropriate for missing months (e.g., no activity vs. missing data). Also, mention that you would test edge cases like division by zero when computing percent change.

1. Clarify metric and assumptions

Define weighted engagement (e.g., sum of weighted interactions) and state assumptions about multiple interactions on the same post (e.g., each interaction counts separately or deduplicated per user per post) and timezone boundaries (e.g., UTC or user-local).

2. Generate month calendar CTE

Create a CTE that generates a series of months covering the relevant period, ensuring all months are represented even if no data exists, to handle missing months as zero.

3. Aggregate weighted engagement per source per month

Join the calendar CTE with the engagement data, group by month and content source, and compute the sum of weighted engagement, filling missing months with zero.

4. Apply LAG and compute percent change

Use the LAG window function to get the previous month's weighted engagement for each source, then calculate the month-over-month percent change, handling division by zero.

5. Validate and explain edge cases

Discuss how you would validate the results, handle timezone conversions, and address potential issues like multiple interactions and missing data.

Key Points to Mention

  • Definition of weighted engagement and how weights are assigned (e.g., likes=1, comments=2, shares=3).
  • Handling multiple interactions on the same post: whether to count each interaction separately or deduplicate per user per post.
  • Timezone boundaries: using UTC or user-local time, and how to convert timestamps to months consistently.
  • Month calendar CTE: generating a complete series of months to avoid gaps and zero-filling missing months.
  • LAG function: partitioning by content source and ordering by month to get previous month's value.
  • Percent change calculation: formula ((current - previous) / previous) * 100 and handling division by zero (e.g., using NULLIF or CASE).

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