← Notion Interview Insights

Notion·Software Engineer·Technical Phone Screen·Senior

Senior
Apr 2026

Summary

Interviewed for a Data Engineer role at Notion and got hit with a pretty involved SQL window function problem. The kind of question that sounds manageable until you're actually writing it out under pressure.

Questions Asked (1)

Q1

Given a bids table with columns for bid ID, user ID, product ID, and bid time, write a query to find for each (user, product) pair: (a) the total number of consecutive bid sequences of length 3 or more by that user on that product, and (b) the longest such consecutive sequence. Consecutive means no other user's bid on the same product appears in between, ordered by bid time.

Data ModelingAlgorithms & Data StructuresProduct Analytics & Metrics
Author's notes

The streak detection trick is the classic double ROW_NUMBER approach.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use window functions to assign a row number per product ordered by bid time, then compute the difference between that row number and a row number per (product, user) to create a group identifier for consecutive runs. Filter groups with length >= 3, then aggregate to count sequences and find the maximum length per (user, product).

Pro tip: Mention that this pattern is a classic 'gaps and islands' problem, and that using ROW_NUMBER() differences is the most efficient and scalable approach, especially for large datasets like Notion's.

1. Understand the problem and define consecutive sequences

Clarify that a consecutive sequence for a (user, product) means a run of bids by that user on that product with no other user's bid on the same product in between, ordered by bid time.

2. Assign row numbers to identify gaps

Use ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY bid_time) as global_rank, and ROW_NUMBER() OVER (PARTITION BY product_id, user_id ORDER BY bid_time) as user_rank. The difference (global_rank - user_rank) remains constant within a consecutive run for that user.

3. Group consecutive bids into sequences

Group by product_id, user_id, and the difference (global_rank - user_rank) to form sequences. Count the number of bids in each group to get sequence lengths.

4. Filter and aggregate results

Filter groups where sequence length >= 3. Then, for each (user, product), count the number of such sequences and find the maximum sequence length.

5. Write the final SQL query

Combine the steps into a single SQL query using CTEs or subqueries, ensuring proper ordering and aggregation.

Key Points to Mention

  • Use of window functions (ROW_NUMBER) to assign ranks within partitions.
  • The 'gaps and islands' technique: difference of row numbers identifies consecutive groups.
  • Partitioning by product_id and user_id appropriately.
  • Filtering sequences of length >= 3 before aggregation.
  • Aggregating to count sequences and find the longest sequence per (user, product).
  • Consider performance implications and indexing on (product_id, bid_time) and (product_id, user_id, bid_time).

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