I have some data. I want to group them based on the value of data
column. If there are 3 or more consecutive rows that have data bigger than 10, then those rows
First, we discount any row that has a value of 10 or less:
WITH t10 AS (SELECT * FROM t WHERE data > 10),
Next, get the rows whose immediate predecessor is also more than 10:
okleft AS (SELECT t10.*, pred.id AS predid FROM
t10
INNER JOIN t pred ON
pred.[when] < t10.[when]
AND pred.[when] >= ALL (SELECT [when] FROM t t2 WHERE t2.[when] < t10.[when])
WHERE pred.data > 10
),
Also get the rows whose immediate successor is also more than 10:
okright as (SELECT t10.*, succ.id AS succid FROM
t10
INNER JOIN t succ ON
succ.[when] > t10.[when]
AND succ.[when] <= ALL (SELECT [when] FROM t t2 WHERE t2.[when] > t10.[when])
WHERE succ.data > 10
),
Finally, select any row where it either starts a sequence of 3, is in the middle of one, or ends one:
A row whose valid right side also has a valid right side starts a sequence of at least 3:
starts3 AS (SELECT id, [when], data FROM okright r1 WHERE EXISTS(
SELECT NULL FROM okright r2 WHERE r2.id = r1.succid)),
A row whose predecessor and successor are both valid is in the middle of at least 3:
mid3 AS (SELECT id, [when], data FROM okleft l WHERE EXISTS(
SELECT NULL FROM okright r WHERE r.id = l.id)),
A row whose valid left side also has a valid left side ends a sequence of at least 3:
ends3 AS (SELECT id, [when], data FROM okleft l1 WHERE EXISTS(
SELECT NULL FROM okleft l2 WHERE l2.id = l1.predid))
Join them all up, with UNION to remove duplicates:
SELECT * FROM starts3
UNION SELECT * FROM mid3
UNION SELECT * FROM ends3
SQL Fiddler: http://sqlfiddle.com/#!3/12f3a/9
Edit: I like BVR's answer, much more elegant than mine.