It is a bit complicated, but try this:
;with a as
(
select [ID], [Type], row_number() over (order by ID) rn from @DataSource
), b as
(
select [ID], [Type], rn, cast(1 as int) lvl from a where rn = 1
union all
select a.[ID], a.[Type],a.rn, case when a.[Type] = 'S' then 1 when a.[Type] = 'E' then -1 else 0 end + lvl
from a
join b on a.rn = b.rn + 1
),
c as
(
select [ID], [Type], row_number() over (partition by [type] order by lvl,rn) grp
from b
)
select c1.id S, c2.id E from c c1
join c c2
on c1.grp = c2.grp
where c1.[type] = 'S' and c2.[type] = 'E'
order by c1.id
option( maxrecursion 0)
Result:
S E
3 6
7 14
10 13
15 30
16 29
17 28
19 27
20 26
31 46
32 35
36 38
39 45
40 44
EDIT: because you are using sqlserver 2012, the script can be simplified, I also added an improvement for performance. I hope this works in your case. Script now assume that 'S' is always before 'E'.
;with a as
(
select [ID], [Type],
sum(case when [type]='S' then 1 when [type]='E' then -1 end)over(order by id) lvl
from @DataSource
), b as
(
select [ID], [Type],
row_number() over (partition by [type] order by lvl,id) grp
from a
)
select min(id) S, max(id) E
from b
group by grp
order by s