Reputation: 21
I have the following table:
Row Column Type
1 1 =
1 2 =
1 3 O
1 4 =
1 5 =
1 6 O
2 1 =
And I need to get something like that
Row Start_Column End_Column Type
1 1 2 =
1 3 3 O
1 4 5 =
1 6 6 O
2 1 1 =
I tried to group it, to manipulate with ROW_NUMBER, RANK but with no luck
Does anyone have any idea how to do this?
Upvotes: 1
Views: 65
Reputation: 1269773
This is a type of gaps-and-islands problem. In this case, the simplest method is probably the difference of row numbers:
select row, type, min(column), max(column)
from (select t.*,
row_number() over (partition by row, type order by column) as seqnum_2,
row_number() over (partition by row order by column) as seqnum
from t
) t
group by row, type, (seqnum - seqnum_2)
order by row, min(column);
If column
is sequential with no gaps, you can simplify this even more:
select row, type, min(column), max(column)
from (select t.*,
row_number() over (partition by row, type order by column) as seqnum_2
from t
) t
group by row, type, (column - seqnum_2)
order by row, min(column);
Why does this work? Well, if you subtract an increasing sequence from column
, then the result is constant -- when the types are the same.
Here is a db<>fiddle.
Upvotes: 2
Reputation: 164099
You can use LAG()
and SUM()
window functions to create the groups that you want and then aggregate:
SELECT [Row],
MIN([Column]) Start_Column,
MAX([Column]) End_Column,
MAX([Type]) [Type]
FROM (
SELECT *, SUM(flag) OVER (PARTITION BY [Row] ORDER BY [Column]) grp
FROM (
SELECT *,
CASE WHEN [Type] = LAG([Type]) OVER (PARTITION BY [Row] ORDER BY [Column]) THEN 0 ELSE 1 END flag
FROM tablename
) t
) t
GROUP BY [Row], grp
ORDER BY [Row], grp
See the demo.
Results:
Row | Start_Column | End_Column | Type
--- | ------------ | ---------- | ----
1 | 1 | 2 | =
1 | 3 | 3 | O
1 | 4 | 5 | =
1 | 6 | 6 | O
2 | 1 | 1 | =
Upvotes: 2