Gaps and islands is a SQL pattern for grouping ordered rows into continuous runs (islands) and finding the breaks between them (gaps): the periods a machine reported the same status, the days a user was active in a row, or the hours a sensor went silent. The standard solutions all turn each run into a constant group id. For runs of an equal value, subtract a row number within each status from a row number over the whole sequence. For consecutive days, subtract a row number from the date. For anything else, flag each row that starts a new run with LAG and turn the flags into group ids with a running SUM.
In an FDE interview
Uptime, streak and sessionization questions over event or heartbeat data are all gaps-and-islands problems. Before writing SQL, pin down what “continuous” means for this customer: is a missing day a break, and is a silence of gap > interval '15 minutes' an outage or a slow sensor?
Then pick the technique on purpose. The date-minus-row-number form suits consecutive days, and it needs DENSE_RANK rather than ROW_NUMBER when a day can appear twice. The LAG plus running-sum form handles a threshold on the gap and is the same shape as sessionizing clicks. The status-run and LAG forms need a unique order, so add a tiebreaker column when timestamps can repeat: rows that tie on every ORDER BY column are peers, and with the default frame a running SUM gives them all the same value (SQLite, window functions).
The gaps between rows are easy; the gap after the last row is not. A device that is down right now has no next heartbeat, so compare its last reading with the current time (now() in PostgreSQL), and generate a date spine when the answer must list days with no rows at all.
Grouping page views into sessions takes the threshold form, and a planned SQL drill, stockout streaks, will take the consecutive-days form.