Skip to content
Reliable Data Engineering
Practice problem hard intervalsgaps-and-islandsrunning-max
Solve it in the browser (SQL editor)

Merge Overlapping Subscription Periods

Difficulty: Hard · Topics: intervals, gaps-and-islands, running-max · Asked at: Netflix, Spotify, Amazon, Apple

Problem

Users can hold overlapping subscriptions. Merge each user’s periods into continuous coverage: periods that overlap or touch (next start ≤ previous end) merge. Return user_id, coverage_start, coverage_end, total_days (end − start), ordered by user and start.

Schema and sample data

CREATE TABLE subscriptions (user_id INTEGER, start_date TEXT, end_date TEXT);
INSERT INTO subscriptions VALUES
(1,'2026-01-01','2026-01-31'),(1,'2026-01-15','2026-02-15'),(1,'2026-02-15','2026-03-01'),(1,'2026-04-01','2026-04-30'),
(2,'2026-01-01','2026-12-31'),(2,'2026-03-01','2026-03-31'),(2,'2027-01-05','2027-01-10'),
(3,'2026-05-01','2026-05-10');

Expected output

user_idcoverage_startcoverage_endtotal_days
12026-01-012026-03-0159
12026-04-012026-04-3029
22026-01-012026-12-31364
22027-01-052027-01-105
32026-05-012026-05-109

Hints

Hint 1

Sort by start. A period starts a new group if its start is after the max end of all previous periods (not just the previous row: think of user 2).

Hint 2

Running MAX over ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING, then flag + running sum.

Solution

WITH o AS (
  SELECT *,
         MAX(end_date) OVER (PARTITION BY user_id ORDER BY start_date, end_date
                             ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS prev_max_end
  FROM subscriptions
), g AS (
  SELECT *,
         SUM(CASE WHEN prev_max_end IS NULL OR start_date > prev_max_end THEN 1 ELSE 0 END)
           OVER (PARTITION BY user_id ORDER BY start_date, end_date ROWS UNBOUNDED PRECEDING) AS grp
  FROM o
)
SELECT user_id, MIN(start_date) AS coverage_start, MAX(end_date) AS coverage_end,
       CAST(julianday(MAX(end_date)) - julianday(MIN(start_date)) AS INTEGER) AS total_days
FROM g
GROUP BY user_id, grp
ORDER BY user_id, coverage_start;

Explanation

Comparing only with the previous row’s end fails for user 2: the March subscription ends before the next one starts, but the yearly subscription still covers it. The running max end of everything before is the correct “current coverage end”. Same algorithm as LeetCode 56 (merge intervals), expressed in SQL.

Follow-up questions

Compute total distinct covered days per user (overlaps counted once).

Sum total_days (or +1 for inclusive ends) of the merged periods.

How does this change if adjacent periods (end = Jan 31, next start = Feb 1) should merge too?

Change the new-group condition to start_date > DATE(prev_max_end, '+1 day').