← Stripe Interview Insights

Stripe·Data Scientist·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
May 2026Remote

Summary

Stripe DS interview was a single deep-dive SQL/ETL design session. The whole thing was one sprawling problem about building a rerunnable pipeline on top of a fact table, and it went places I did not fully expect. Walked out unsure whether I nailed it or just survived it.

Questions Asked (5)

Q1

Write SQL CTEs that deduplicate events_raw by event_id keeping only the row with the highest ingested_at, and deduplicate orders_raw by order_id keeping the row with the highest updated_at. Then explain why deduping on natural keys like event_id is safer than using ROW_NUMBER over (u_id, event_ts).

Data ModelingTechnical Trade-offs
Author's notes

The ROW_NUMBER angle is where I fumbled a bit.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by writing two separate CTEs that use ROW_NUMBER() partitioned by the natural key and ordered by the timestamp descending, then filter to rn=1. After presenting the SQL, explain that deduping on natural keys like event_id is safer because it preserves the intended uniqueness constraint and avoids accidentally collapsing distinct events that share the same user and timestamp.

Pro tip: Mention that in production you'd also consider using QUALIFY (if supported) or a MERGE for incremental deduping, and that you'd validate the dedupe logic by checking for duplicate counts before and after.

1. Write the deduplication CTE for events_raw

Use ROW_NUMBER() OVER (PARTITION BY event_id ORDER BY ingested_at DESC) and filter to rn=1 to keep the latest ingested row per event_id.

2. Write the deduplication CTE for orders_raw

Use ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY updated_at DESC) and filter to rn=1 to keep the most recently updated row per order_id.

3. Explain the natural key deduplication rationale

Argue that event_id is the true unique identifier for an event, so deduping on it ensures we keep one record per actual event. Using (u_id, event_ts) assumes uniqueness that may not hold and can drop legitimate distinct events.

4. Discuss trade-offs and edge cases

Acknowledge that natural keys may have duplicates due to ingestion issues, but that's exactly what deduping should fix. Also mention that if event_id is not unique, you need to investigate data quality.

5. Summarize with a recommendation

Conclude that deduping on natural keys is safer because it aligns with the business definition of uniqueness and avoids unintended data loss.

Key Points to Mention

  • Use of ROW_NUMBER() with PARTITION BY and ORDER BY DESC to rank rows.
  • Filtering to rn=1 to keep the latest record.
  • Natural key (event_id) represents the true unique identity of an event.
  • Composite key (u_id, event_ts) may not be unique and can cause accidental deduplication of distinct events.
  • Deduping on natural keys preserves data integrity and aligns with business logic.
  • Validation: compare row counts before and after to ensure only intended duplicates are removed.

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

Q2

Using your deduped CTEs, write a SELECT that produces one row per non-test user for a given date D, computing first_event_ts, events_cnt, paid_orders_cnt, and paid_orders_amt. Orders should only count if the latest status is paid, shipped, or completed, not refunded or canceled.

Data ModelingProduct Analytics & Metrics
Author's notes

Pretty mechanical once the dedup CTEs are in place, but I forgot to filter out is_test = 1 users on my first pass and they caught it.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by aggregating events and orders per user for date D, then join these aggregates to a filtered user dimension that excludes test users. For orders, first determine the latest status per order, then filter to only paid, shipped, or completed statuses before aggregating counts and amounts. Finally, combine the metrics into a single row per user.

Pro tip: Explicitly handle users with no events or orders by using LEFT JOINs and COALESCE to avoid dropping them, and clarify that 'latest status' should be based on the most recent status update timestamp, not order creation time.

1. Filter non-test users

Select user_id from the deduped users CTE where is_test = false (or equivalent flag). This defines the population for the final output.

2. Aggregate events per user

From the deduped events CTE, filter to date D, then compute first_event_ts (MIN event timestamp) and events_cnt (COUNT of events) per user.

3. Determine latest order status

From the deduped orders CTE, use a window function (e.g., ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY status_updated_at DESC)) to get the latest status per order.

4. Aggregate paid orders per user

Filter the latest-status orders to only those with status IN ('paid', 'shipped', 'completed'), then compute paid_orders_cnt (COUNT) and paid_orders_amt (SUM of amount) per user for date D.

5. Combine metrics into final SELECT

LEFT JOIN the non-test users with the event and order aggregates on user_id, using COALESCE to replace NULLs with 0 for counts and amounts, and output one row per user.

Key Points to Mention

  • Use of deduped CTEs to ensure no duplicate events or orders.
  • Filtering out test users via a flag or email pattern.
  • Handling of users with no events or orders using LEFT JOIN and COALESCE.
  • Determining latest order status with a window function ordered by status update timestamp.
  • Filtering orders to only paid, shipped, or completed statuses (excluding refunded/canceled).
  • Aggregating metrics per user for a specific date D, ensuring date filters are applied correctly.

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

Q3

Records for date D can arrive up to 2 days late. Describe and write SQL for an incremental approach that recomputes partitions for a rolling window on each run date, then merges only the target partition. Show a MERGE or INSERT OVERWRITE example and explain how it stays idempotent on reruns.

System DesignTechnical Trade-offs
Author's notes

This was the part I actually felt okay about.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by explaining the late-arriving data problem and the need for incremental processing. Describe a rolling window approach that recomputes the last 3 days (D-2 to D) on each run date, then merges only the target partition (e.g., D-2) to avoid full table scans. Provide SQL using MERGE or INSERT OVERWRITE with partition pruning, and emphasize idempotency by ensuring the merge condition matches on the primary key and the operation is deterministic.

Pro tip: Mention that you would use a MERGE statement with a deterministic condition and that you would also consider using INSERT OVERWRITE for the specific partition if the data is immutable. Highlight that idempotency is achieved because rerunning the same logic on the same data produces the same result, and the merge only affects the target partition.

1. Understand the problem and requirements

Clarify that records for date D can arrive up to 2 days late, so partitions for D-2, D-1, and D may change. The goal is to incrementally update only the affected partition (D-2) on each run date.

2. Design the incremental approach

On each run date, recompute the last 3 days (D-2, D-1, D) from the source to capture late data, but only merge the target partition D-2 into the final table. This limits the write scope and maintains performance.

3. Write SQL for recomputation and merge

Use a CTE to recompute the rolling window, then apply a MERGE or INSERT OVERWRITE to update only the target partition. Ensure the merge condition uses a unique key and partition filter.

4. Explain idempotency

Show that rerunning the same job on the same run date produces the same result because the merge is deterministic and only affects the target partition. If using INSERT OVERWRITE, it replaces the partition entirely, ensuring idempotency.

5. Discuss trade-offs and alternatives

Mention that MERGE is more flexible for updates/deletes but may be slower; INSERT OVERWRITE is faster for full partition replacement. Consider partitioning strategy and data volume.

Key Points to Mention

  • Late-arriving data handling with a rolling window of 3 days (D-2 to D).
  • Partition pruning to limit recomputation and merge to only the target partition (D-2).
  • Use of MERGE statement with a unique key (e.g., record_id) and partition filter for idempotent updates.
  • Alternative INSERT OVERWRITE for full partition replacement, which is inherently idempotent.
  • Idempotency achieved through deterministic logic and partition-scoped writes.
  • Performance considerations: avoiding full table scans, using partition pruning, and choosing between MERGE and INSERT OVERWRITE based on data mutability.

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

Q4

Enumerate at least five edge cases your ETL must handle, such as partial writes, schema drift, null event timestamps, daylight saving time issues, and replayed backfills. For each, describe the defensive technique you'd use.

System DesignTechnical Trade-offs
Author's notes

Five felt like a lot to rattle off under pressure.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by acknowledging that edge cases are inevitable in production ETL and that defensive design is key. Then, for each edge case, briefly describe the scenario and the specific technique you'd use to handle it, emphasizing idempotency, observability, and data quality. Finally, tie it back to Stripe's context of financial data accuracy and reliability.

Pro tip: Prioritize edge cases by business impact and likelihood, and mention how you'd monitor and alert on them. This shows you think beyond just handling them to ensuring they don't silently corrupt data.

1. Identify and Prioritize Edge Cases

List at least five edge cases, such as partial writes, schema drift, null timestamps, DST issues, and replayed backfills. Prioritize them based on potential impact on data integrity and business metrics.

2. Describe Defensive Techniques

For each edge case, explain the defensive technique you'd use, such as idempotent writes, schema validation, default timestamp handling, timezone-aware processing, and backfill versioning.

3. Emphasize Idempotency and Observability

Highlight how techniques like idempotent writes and monitoring ensure data consistency and early detection of issues. Mention logging, metrics, and alerting for each edge case.

4. Connect to Business Context

Relate the edge cases and techniques to Stripe's need for accurate financial reporting and real-time analytics, showing awareness of the domain.

Key Points to Mention

  • Idempotent writes using unique keys or upserts to handle partial writes and replayed backfills
  • Schema drift detection and management via schema registry or versioned schemas
  • Null timestamp handling with default values or event-time processing
  • Daylight saving time issues addressed with UTC timestamps and timezone-aware libraries
  • Backfill strategies with versioning and idempotency to avoid data duplication
  • Monitoring and alerting for data quality issues and pipeline failures

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

Q5

Write two reconciliation queries: one that compares counts and amounts between orders_raw (latest status) and the daily_user_metrics fact table for date D, and one that detects any duplicate event_ids that leaked into the D partition.

Data ModelingRoot Cause Analysis
Author's notes

Validation queries are something I always underestimate in interviews.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the schema and business logic: identify the latest status per order (e.g., using a window function on order_id ordered by updated_at), and understand the grain of daily_user_metrics. Then write two separate queries: one that aggregates orders_raw to match the fact table's grain and compares counts and sums, and another that checks for duplicate event_ids within the date D partition using GROUP BY and HAVING COUNT(*) > 1.

Pro tip: Always validate reconciliation queries against a known-good date first to ensure your logic is correct before applying to the target date; this prevents false alarms and builds trust with stakeholders.

1. Clarify schema and business rules

Ask about the table structures, especially how to determine the latest status (e.g., timestamp column) and the grain of daily_user_metrics (e.g., per user per day). Confirm what 'date D' means for each table.

2. Write count and amount reconciliation query

Use a CTE to get the latest status per order for date D, then aggregate counts and sums. Compare these aggregates to the daily_user_metrics fact table for the same date, highlighting any mismatches.

3. Write duplicate event_id detection query

Query the partition for date D, group by event_id, and filter for groups with count greater than 1. This identifies any duplicate event_ids that should not exist.

4. Consider edge cases and performance

Mention handling of NULLs, timezone differences, and late-arriving data. Also note that using window functions or EXISTS can be more efficient than self-joins for large datasets.

5. Explain how to interpret and act on results

Describe what actions to take if discrepancies are found, such as investigating upstream data pipelines or backfilling missing data, and how to communicate findings to stakeholders.

Key Points to Mention

  • Use of window functions (e.g., ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY updated_at DESC)) to get the latest status per order.
  • Aggregation at the correct grain to match the fact table (e.g., per user per day) before comparison.
  • Full outer join or union of aggregates to identify mismatches in both directions (missing in fact vs. extra in fact).
  • Duplicate detection using GROUP BY event_id HAVING COUNT(*) > 1, and ensuring the query is partition-pruned for performance.
  • Consideration of timezone and date boundaries when filtering for date D.
  • Importance of data quality checks and reconciliation as part of a robust data pipeline.

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