Example 1
Create a run group id for consecutive status rows ordered by timestamp
Within each account, the first ROW_NUMBER() counts every event in timestamp order, while the second counts only rows within the same status. Their difference stays constant for each consecutive run of the same status. The important caveat is that group_offset alone is not the full identifier when a status value appears again later, so the practical run key is (status, group_offset) or the derived group_id. If two rows can share the same timestamp, add another stable tie-breaker to the ORDER BY so the sequence remains deterministic.
CREATE TABLE device_events (
account VARCHAR(20),
event_timestamp DATETIME,
status VARCHAR(20)
);
INSERT INTO
device_events (account, event_timestamp, status)
VALUES
('alpha', '2026-04-01 09:00:00', 'online'),
('alpha', '2026-04-01 09:05:00', 'online'),
('alpha', '2026-04-01 09:10:00', 'offline'),
('alpha', '2026-04-01 09:15:00', 'offline'),
('alpha', '2026-04-01 09:20:00', 'online'),
('beta', '2026-04-01 10:00:00', 'online'),
('beta', '2026-04-01 10:05:00', 'offline'),
('beta', '2026-04-01 10:10:00', 'offline'),
('beta', '2026-04-01 10:15:00', 'online');WITH
numbered AS (
SELECT
account,
event_timestamp,
status,
ROW_NUMBER() OVER (
PARTITION BY
account
ORDER BY
event_timestamp
) - ROW_NUMBER() OVER (
PARTITION BY
account,
status
ORDER BY
event_timestamp
) AS group_offset
FROM
device_events
)
SELECT
account,
event_timestamp,
status,
group_offset,
CONCAT (status, '-', group_offset) AS group_id
FROM
numbered
ORDER BY
account,
event_timestamp;| account | event_timestamp | status | group_offset | group_id |
|---|---|---|---|---|
| alpha | 2026-04-01 09:00:00 | online | 0 | online-0 |
| alpha | 2026-04-01 09:05:00 | online | 0 | online-0 |
| alpha | 2026-04-01 09:10:00 | offline | 2 | offline-2 |
| alpha | 2026-04-01 09:15:00 | offline | 2 | offline-2 |
| alpha | 2026-04-01 09:20:00 | online | 2 | online-2 |
| beta | 2026-04-01 10:00:00 | online | 0 | online-0 |
| beta | 2026-04-01 10:05:00 | offline | 1 | offline-1 |
| beta | 2026-04-01 10:10:00 | offline | 1 | offline-1 |
| beta | 2026-04-01 10:15:00 | online | 2 | online-2 |
The example uses timestamp ordering to derive consecutive-run groups consistently across all supported engines.