← Amazon Interview Insights

Amazon·Data Scientist·Technical Phone Screen·Intermediate

IntermediatePrefer not to say
Jun 2026Remote

Summary

Amazon data scientist technical screen, heavy on SQL and pandas. Three big problem sets back to back, all on the same two tables. Not a vibe check at all, just pure technical depth for an hour.

Questions Asked (6)

Q1

Given a subscriptions table with known data quality issues, write SQL queries to rigorously validate four assumptions: only 'active' and 'inactive' are valid statuses, the combination of subscription_id and status_date is unique, status dates are strictly increasing per subscription, and no subscription has more than one status on the same calendar day. Return the actual violating rows for each check.

Data ModelingRoot Cause Analysis
Author's notes

This was the one that got me.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the table schema and the exact meaning of each assumption, then write a separate SQL query for each validation check that returns the violating rows. Use window functions and aggregation to detect duplicates, invalid values, and ordering violations, and explain how each query maps to the assumption.

Pro tip: Mention that you would run these checks as part of a data quality pipeline and set up alerts for violations, showing you think about production monitoring rather than one-off analysis.

1. Clarify schema and assumptions

Confirm column names, data types, and the precise definition of each assumption (e.g., what 'status_date' represents, whether it includes time). This ensures your queries target the right columns and logic.

2. Check valid status values

Write a query that selects rows where status is not 'active' or 'inactive'. Use a simple WHERE clause with NOT IN to return all violating rows.

3. Check uniqueness of subscription_id and status_date

Use GROUP BY with HAVING COUNT(*) > 1 to find duplicate combinations, then join back to the original table to return the full violating rows.

4. Check strictly increasing status dates per subscription

Use the LAG window function partitioned by subscription_id ordered by status_date to compare each row's date with the previous one. Return rows where the current date is not greater than the previous date.

5. Check no more than one status per calendar day

Group by subscription_id and DATE(status_date) and use HAVING COUNT(*) > 1 to find violations, then join back to return the actual rows. This is similar to step 3 but at the day level.

Key Points to Mention

  • Use of window functions like LAG to detect ordering violations
  • Importance of returning actual violating rows, not just counts
  • Handling of NULLs and edge cases (e.g., missing dates, invalid formats)
  • Performance considerations for large tables (indexes, partitioning)
  • Integration with data quality monitoring and alerting
  • Clear mapping of each query to the corresponding assumption

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

Q2

Using the same subscriptions table and a reference date of 2025-09-01, write SQL to return each subscription_id's latest known status and the date that status took effect.

Data Modeling
Author's notes

Straightforward once you've done the data quality part.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the table schema and the meaning of 'latest known status' as of the reference date 2025-09-01. Then use a window function like ROW_NUMBER() partitioned by subscription_id and ordered by effective_date descending to pick the most recent status on or before that date. Finally, return subscription_id, status, and effective_date for the top-ranked row per subscription.

Pro tip: Explicitly state your assumption that the table has subscription_id, status, and effective_date columns, and that status changes are recorded as new rows with effective dates. This shows you think about data model semantics before writing SQL, which is exactly what Amazon values in data scientists.

1. Clarify schema and business logic

Confirm the table columns (subscription_id, status, effective_date) and that each row represents a status change effective from that date. Ask whether future-dated statuses exist and should be excluded.

2. Filter to relevant records

Apply a WHERE clause to keep only rows where effective_date <= '2025-09-01', ensuring you only consider statuses known by the reference date.

3. Rank statuses per subscription

Use ROW_NUMBER() OVER (PARTITION BY subscription_id ORDER BY effective_date DESC) to assign rank 1 to the latest status for each subscription.

4. Select the latest status

Wrap the ranked query in a CTE or subquery and filter for rank = 1, then select subscription_id, status, and effective_date.

5. Validate and discuss edge cases

Mention handling ties (e.g., same effective_date) and subscriptions with no status before the reference date, and confirm the output format.

Key Points to Mention

  • Use of window functions (ROW_NUMBER or RANK) for latest-record-per-group problems
  • Filtering by effective_date <= reference_date to respect the 'as of' requirement
  • Partitioning by subscription_id and ordering by effective_date descending
  • Handling ties or duplicate effective dates (e.g., using ROW_NUMBER with a tiebreaker or RANK)
  • Excluding future-dated status changes that are not yet effective
  • Considering subscriptions with no status before the reference date (e.g., use LEFT JOIN or COALESCE if needed)

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

Q3

In pandas, build a DataFrame with columns subscription_id, first_active_date, and last_inactive_date. First active date is the minimum status_date where status is 'active'; last inactive date is the most recent status_date where status is 'inactive' on or before 2025-09-01. Handle duplicates, unexpected statuses, and nulls when a subscription has no qualifying rows.

Data ModelingProduct Analytics & Metrics
Author's notes

Filtering out unexpected statuses before the groupby is the part people probably miss.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the data schema and edge cases, then outline a pandas solution using groupby and conditional aggregation. Emphasize handling duplicates, unexpected statuses, and nulls to ensure robustness. Finally, discuss validation and performance considerations.

Pro tip: Mention that you would first inspect the data distribution and status values to catch unexpected statuses early, and use vectorized operations instead of apply for scalability.

1. Clarify requirements and data schema

Confirm the input DataFrame structure, expected status values, and how to handle duplicates and nulls. Ask about the definition of 'most recent' and whether dates are inclusive.

2. Preprocess and clean data

Handle duplicates by dropping or aggregating, filter out unexpected statuses, and decide on null handling (e.g., drop rows with null status_date or status).

3. Compute first active date

Filter for status == 'active', then group by subscription_id and compute the minimum status_date. Use groupby and min aggregation.

4. Compute last inactive date

Filter for status == 'inactive' and status_date <= '2025-09-01', then group by subscription_id and compute the maximum status_date.

5. Merge and handle missing values

Merge the two results on subscription_id with an outer join, and fill missing dates with NaT or a sentinel value. Validate the output.

Key Points to Mention

  • Use groupby with min and max for efficient aggregation.
  • Handle duplicates by dropping duplicates on (subscription_id, status_date, status) or using drop_duplicates.
  • Filter unexpected statuses early to avoid incorrect aggregations.
  • Use pd.to_datetime for date parsing and ensure proper comparison with the cutoff date.
  • Consider using merge with how='outer' to include subscriptions that only have active or only inactive records.
  • Validate results by checking counts and spot-checking edge cases.

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

Q4

Using a pandas orders DataFrame, identify all customers who either placed fewer than 2 total orders or whose total order amount across all time is under 100.00.

Product Analytics & Metrics
Author's notes

Easy part of the whole interview.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, aggregate the orders DataFrame by customer to compute total order count and total order amount. Then apply a boolean condition to filter customers where order count < 2 OR total amount < 100.00, and return the list of customer IDs.

Pro tip: Clarify whether 'total order amount' includes cancelled or refunded orders, and mention that you'd handle ties or missing data appropriately. Also, consider using a single groupby.agg to compute both metrics efficiently.

1. Understand the data and requirements

Inspect the orders DataFrame to identify columns for customer ID, order ID, and order amount. Clarify any ambiguities like time range, order status, and currency.

2. Aggregate per customer

Group by customer ID and compute the total number of orders (count of order IDs) and the total order amount (sum of order amounts).

3. Apply the filter condition

Create a boolean mask where total orders < 2 OR total amount < 100.00, and select customers that satisfy either condition.

4. Return and validate results

Extract the customer IDs from the filtered DataFrame. Optionally, validate by checking edge cases (e.g., customers with exactly 2 orders and exactly 100.00 total).

Key Points to Mention

  • Use groupby with agg to compute both count and sum in one pass.
  • Handle potential missing or null values in order amounts or customer IDs.
  • Clarify whether 'total order amount' should include all orders or only completed ones.
  • Consider performance implications for large datasets (e.g., using vectorized operations).
  • Ensure the condition is OR, not AND, and explain the logic.
  • Mention that the result should be a list or set of unique customer IDs.

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

Q5

For each calendar month derived from order_date, produce two ranked leaderboards: top 5 customers by order count and top 5 customers by total order amount. Tie-break by higher total amount first, then lower cust_id. Return all customers if fewer than 5 exist in that month.

Product Analytics & MetricsAlgorithms & Data Structures
Author's notes

The tie-breaking rules are where this gets annoying.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a SQL query with window functions to rank customers within each month by order count and total amount, applying the specified tie-breakers. Then filter to top 5 per ranking per month, ensuring all customers are returned if fewer than 5 exist.

Pro tip: Clarify whether 'order count' means distinct orders or total items, and confirm that tie-breaking applies to both leaderboards. Also, mention that using ROW_NUMBER() with proper partitioning and ordering handles ties deterministically.

1. Aggregate per customer per month

Compute total order count and total order amount for each customer in each month using GROUP BY on customer and month.

2. Apply ranking with tie-breakers

Use window functions (e.g., ROW_NUMBER() or RANK()) partitioned by month, ordered by the metric descending, then total amount descending, then cust_id ascending.

3. Filter top 5 per leaderboard

Select rows where the rank is <= 5 for each ranking type, ensuring that if fewer than 5 customers exist, all are included.

4. Combine results

Union or join the two leaderboards, labeling each row with the leaderboard type (order count or total amount) for clarity.

Key Points to Mention

  • Use of window functions (ROW_NUMBER, RANK) for ranking within partitions.
  • Proper handling of ties with multiple ordering criteria (metric DESC, total amount DESC, cust_id ASC).
  • Partitioning by month to reset rankings for each calendar month.
  • Ensuring all customers are returned when fewer than 5 exist (no artificial padding).
  • Distinction between order count and total order amount, and how they are computed.
  • Efficiency considerations: aggregating before ranking to reduce data size.

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

Q6

Compute each customer's total spend broken down by product type and pivot the result into a wide table with columns cust_id, camera, shoes, laptop, and clothes. Fill missing product combinations with 0.00.

Data ModelingProduct Analytics & Metrics
Author's notes

Pivot table question.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, aggregate total spend per customer and product type using a GROUP BY or conditional aggregation. Then pivot the result into a wide format using conditional SUM (CASE WHEN) or a pivot function, ensuring all product types become columns and missing values are filled with 0.00. Finally, validate the output for correctness and completeness.

Pro tip: Explicitly handle NULLs with COALESCE or IFNULL to avoid unexpected NULLs in the final output, and consider performance implications of pivoting large datasets by filtering early or using efficient aggregation.

1. Aggregate spend per customer and product type

Use a GROUP BY on customer ID and product type to sum the spend, or use conditional aggregation if pivoting directly. Ensure you handle any NULLs in spend appropriately.

2. Pivot to wide format

Transform the long format into wide format using conditional SUM (CASE WHEN product_type = 'camera' THEN spend ELSE 0 END) for each product type, or use a PIVOT function if supported by your SQL dialect.

3. Fill missing combinations with 0.00

After pivoting, any customer-product combination that had no spend will result in NULL. Use COALESCE or IFNULL to replace NULLs with 0.00, ensuring the output matches the required format.

4. Validate and format output

Check that all customers are included and that the columns are exactly cust_id, camera, shoes, laptop, clothes. Ensure numeric values are properly formatted to two decimal places.

Key Points to Mention

  • Use of conditional aggregation (CASE WHEN) for pivoting in SQL
  • Handling NULLs with COALESCE or IFNULL to fill missing values with 0.00
  • Ensuring correct grouping by customer ID and product type
  • Performance considerations: filtering early, indexing, or using efficient aggregation
  • Validation of results: checking row counts, spot-checking totals, and ensuring all product types are represented
  • Awareness of SQL dialect differences (e.g., PIVOT function availability)

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