← eBay Interview Insights

eBay·Software Engineer·Technical Phone Screen·Intermediate

Intermediate
Jun 2026

Summary

SQL-heavy technical screen for a Software Engineer role at eBay. The whole thing was basically one big window functions question broken into parts, which sounds manageable until you're actually writing ROWS BETWEEN framing live on a shared editor.

Questions Asked (3)

Q1

Given a table with user events (user_id, event_time, event_type, value), write SQL to compute each user's rolling 7-day sum of value by day using window functions.

Data ModelingTechnical Trade-offsSystem Design
Author's notes

I knew the general shape: PARTITION BY user_id, ORDER BY day, then ROWS BETWEEN 6 PRECEDING AND CURRENT ROW.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, aggregate the raw events into daily sums per user to reduce data volume, then apply a window function with a RANGE frame covering the current day and the preceding 6 days to compute the rolling 7-day sum. Ensure the window is partitioned by user_id and ordered by day, and handle missing days appropriately.

Pro tip: Mention that using RANGE with INTERVAL '6 days' PRECEDING correctly handles gaps in dates, unlike ROWS which would count rows instead of days. Also, clarify that the rolling sum should include the current day, so the frame is BETWEEN 6 PRECEDING AND CURRENT ROW.

1. Clarify requirements

Confirm the definition of 'rolling 7-day sum': does it include the current day? Should days with no events be included? What is the expected output granularity (per user per day)?

2. Aggregate daily values

Write a subquery or CTE that groups by user_id and date (truncated from event_time) and sums the value column to get daily totals per user.

3. Apply window function

Use SUM(daily_value) OVER (PARTITION BY user_id ORDER BY day RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW) to compute the rolling 7-day sum.

4. Handle edge cases

Consider how to handle users with fewer than 7 days of data, missing dates, and time zone conversions. Optionally, generate a date spine to fill gaps if needed.

5. Optimize and validate

Discuss indexing on (user_id, event_time), partitioning strategies for large datasets, and validate results with sample data.

Key Points to Mention

  • Use of RANGE instead of ROWS to correctly handle date gaps and ensure the window covers exactly 7 calendar days.
  • The importance of aggregating daily sums first to avoid double-counting and improve performance.
  • Partitioning by user_id and ordering by date to compute per-user rolling sums.
  • Handling of missing days: either accept gaps or use a date spine to generate a continuous series.
  • Performance considerations: indexing, partitioning, and avoiding unnecessary data shuffling.
  • Clarifying whether the rolling sum should include the current day and how to define the 7-day window (e.g., 6 preceding days + current day).

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

Q2

Using the same events table, rank each user's events chronologically with deterministic tie-breaking.

Algorithms & Data StructuresData Modeling
Author's notes

Pretty quick to answer.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a window function like ROW_NUMBER() partitioned by user_id and ordered by event_timestamp with a deterministic tie-breaker (e.g., event_id). Explain that this ensures each event gets a unique rank per user, and discuss how the tie-breaker prevents non-deterministic results.

Pro tip: Mention that without a unique tie-breaker, the ranking can vary between executions, which is unacceptable in production. Also, consider performance implications: partitioning and ordering large datasets may require appropriate indexing or distribution strategies.

1. Clarify requirements

Confirm that 'rank' means assigning a unique sequential number per user, and that ties should be broken deterministically. Ask if there's a preferred tie-breaker column (e.g., event_id) or if one needs to be derived.

2. Choose the right window function

Select ROW_NUMBER() over RANK() or DENSE_RANK() because it guarantees unique ranks even with ties. Explain that RANK() would leave gaps and not provide a strict chronological order.

3. Define the partitioning and ordering

Partition by user_id and order by event_timestamp ascending, then by a unique column like event_id ascending to break ties. This ensures deterministic results.

4. Write the SQL query

Construct the query: SELECT user_id, event_id, event_timestamp, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_timestamp, event_id) AS event_rank FROM events;

5. Discuss edge cases and performance

Address scenarios like duplicate timestamps, null timestamps, and large data volumes. Suggest indexing on (user_id, event_timestamp, event_id) for efficiency.

Key Points to Mention

  • Use of ROW_NUMBER() for unique ranking
  • Partitioning by user_id to rank within each user
  • Ordering by event_timestamp with a deterministic tie-breaker (e.g., event_id)
  • Difference between ROW_NUMBER(), RANK(), and DENSE_RANK()
  • Handling of duplicate timestamps and nulls
  • Performance considerations and indexing strategies

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

Q3

For every event in the table, return the last non-null value seen so far per user. Explain your window framing.

Data ModelingTechnical Trade-offs
Author's notes

This is the one I'd redo.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the table schema, ordering column, and definition of 'last non-null value seen so far' (e.g., per user, ordered by event time). Then explain that you would use a window function like LAST_VALUE with IGNORE NULLS over a partition by user ordered by event time, and discuss the default window frame and why it must be adjusted to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Finally, mention trade-offs such as performance and alternative approaches like self-joins or correlated subqueries.

Pro tip: Demonstrate awareness that the default window frame for LAST_VALUE is RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, which would incorrectly return the last non-null value in the entire partition, not up to the current row. Explicitly stating this shows deep understanding of window framing.

1. Clarify requirements and schema

Ask about the table structure, the ordering column (e.g., event timestamp), and what 'last non-null value seen so far' means (e.g., per user, ordered by time). Confirm whether ties in ordering are possible and how to handle them.

2. Choose the window function and frame

Select LAST_VALUE with IGNORE NULLS (if supported) over a partition by user ordered by event time. Explicitly set the window frame to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW to ensure the function only looks at rows up to the current one.

3. Explain the window framing

Describe why the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) is incorrect for this use case, as it would consider all rows in the partition. Emphasize that the frame must be restricted to the current row.

4. Discuss alternatives and trade-offs

Mention alternative approaches such as using a self-join or correlated subquery, and compare their performance and readability. Note that window functions are generally more efficient and set-based.

5. Consider edge cases and performance

Address handling of nulls, ties in ordering, and large datasets. Suggest indexing the partition and order columns to optimize performance.

Key Points to Mention

  • Use of LAST_VALUE with IGNORE NULLS (or equivalent) to skip nulls.
  • Partition by user and order by event time (or appropriate ordering column).
  • Explicit window frame: ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
  • Default frame pitfall: RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.
  • Alternatives: self-join, correlated subquery, or using MAX with a cumulative approach.
  • Performance considerations: indexing, partitioning, and handling large data.

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