SQL · hard · Asked at Google

Find users who logged in 3 or more consecutive days.

Asked in Data Engineer interviews, in the SQL round.

Short answer

Use ROW_NUMBER and date - row_number as a group key, then count per group.

How to answer it

The gaps-and-islands trick. Number each user's distinct login days in order; subtract that number from the date. Consecutive days produce the same difference, so the difference is a group key for each run.

WITH days AS (
  SELECT DISTINCT user_id, login_date
  FROM logins
),
numbered AS (
  SELECT
    user_id,
    login_date,
    login_date - (ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date))::int AS grp
  FROM days
)
SELECT user_id, MIN(login_date) AS streak_start, COUNT(*) AS streak_days
FROM numbered
GROUP BY user_id, grp
HAVING COUNT(*) >= 3;

Walk one example aloud: logins on the 1st, 2nd, 3rd, 7th get row numbers 1, 2, 3, 4 and differences of day 0, 0, 0, 3. The first three collapse into one group of three; the 7th is its own group of one.

DISTINCT first, because two logins on the same day would get two row numbers and break the arithmetic. In dialects where date minus integer is not allowed, use DATE_SUB or cast to a day number.

Related questions

Practice this for real