Suppose I have this table, named Table
+----+------+------+ | ID | Col1 | Col2 | +----+------+------+ | 1 | A | 0 | | 2 | B | 0 | | 3 | C | 1 | | 4 | A | 1 | | 5 | D | 0 | | 6 | A | 0 | | 7 | F | 1 | | 8 | H | 1 | +----+------+------+
I want this result:
+----+------+------+ | ID | Col1 | Col2 | +----+------+------+ | 3 | C | 1 | | 4 | A | 1 | | 7 | F | 1 | +----+------+------+
That is:
- If
Col1
= A andCol2
= 1, take the corresponding row - If
Col1
= A andCol2
= 0, take the first row below it whereCol2
= 1
I tried something like
SELECT CASE WHEN t.Col2 > 0 THEN t.Col2 WHEN t1.Col2 > 0 THEN t1.Col2 WHEN t2.Col2 > 0 THEN t2.Col2 ... FROM Table t JOIN table t1 ON t.id - 1 = t1.id JOIN table t2 ON t.id - 2 = t2.id ... WHERE t.Col2 = 'A'
but it’s not quite what I was looking for. I couldn’t come up with any solution. What should I do?
Advertisement
Answer
Use window functions SUM() and MIN():
with cte1 as ( select *, sum(case when col1 = 'A' and col2 = 0 then 1 else 0 end) over (order by id) grp from tablename ), cte2 as ( select *, min(case when col2 = 1 then id end) over (partition by grp order by id) next_id from cte1 ) select id, col1, col2 from cte2 where (col1 = 'A' and col2 = 1) or (id = next_id)
See the demo.
Results:
> id | col1 | col2 > -: | :--- | ---: > 3 | C | 1 > 4 | A | 1 > 7 | F | 1