Convert session boundary flags into stable groups.

Section: Gaps and islands

Assign session IDs with a running sum

sql
sql
WITH flagged AS (
  SELECT user_id,
         event_time,
         CASE
           WHEN event_time - LAG(event_time) OVER (
             PARTITION BY user_id
             ORDER BY event_time
           ) > INTERVAL '30 minutes'
           OR LAG(event_time) OVER (
             PARTITION BY user_id
             ORDER BY event_time
           ) IS NULL
           THEN 1 ELSE 0
         END AS is_new_session
  FROM user_events
)
SELECT user_id,
       event_time,
       SUM(is_new_session) OVER (
         PARTITION BY user_id
         ORDER BY event_time
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS session_id
FROM flagged;
Explanation

A cumulative sum transforms boundary rows into session group numbers.

Learn the surrounding workflow

Compare similar commands or jump into common fixes when this command is part of a bigger troubleshooting path.

Related commands

Same sheet · prioritizing Gaps and islands
Flag a new session when the gap is too large
Start a new session after 30 minutes of inactivity.
OpenIn sheetsqlsame section
Group consecutive dates into streaks
Classic islands pattern using row-number arithmetic.
OpenIn sheetsqlsame section
Deduplicate and keep the latest row
Choose one row per business key.
Delete duplicates after ranking
Keep the newest record and remove the rest.