You can do this using an XML path (to combine group values) and grouping by id and activity:
Setting up the MS SQL Server schema :
create table tbl (id varchar(2),activity varchar(10),year int); insert into tbl values ( '01' ,'AAAAA', 2008 ), ( '01' ,'AAAAA', 2009 ), ( '01' ,'AAAAA', 2010 ), ( '01' ,'AAAAA', 2012 ), ( '01' ,'AAAAA', 2013 ), ( '01' ,'AAAAA', 2015 ), ( '01' ,'BBBBB', 2014 ), ( '01' ,'BBBBB', 2015 )
Query
select id, activity, stuff( (select distinct ',' + cast(year as varchar(4)) from tbl where id = t.id and activity=t.activity for xml path ('')) , 1, 1, '') as years from tbl AS t group by id,activity
Results :
| id | activity | years | |----|----------|-------------------------------| | 01 | AAAAA | 2008,2009,2010,2012,2013,2015 | | 01 | BBBBB | 2014,2015 |
Edit after comments and clearly notice the desired result:
if you also want to group sequential, like 2008-2009, then you need additional grouping (the difference of year and rank in each group will give you an excellent nested group):
Query
with cte1 as ( select r = year - (rank() over(partition by id,activity order by year)), id,activity,year from tbl ) ,cte2 as ( select id, activity, cast(min(year) as varchar(4)) + case when min(year)<>max(year) then '-' + cast(max(year) as varchar(4)) else '' end as years from cte1 group by r,id,activity ) select id, activity, stuff( (select distinct ',' + years from cte2 where id = t.id and activity=t.activity for xml path ('')) , 1, 1, '') as years from cte2 AS t group by id,activity
Results :
| id | activity | years | |----|----------|--------------------------| | 01 | AAAAA | 2008-2010,2012-2013,2015 | | 01 | BBBBB | 2014-2015 |