2015-10-16 6 views
5

Próbuję wygenerować konkretny ciąg na podstawie następujących danych za pomocą SQL 2012SQL Sequential Grupowanie i strun do sekwencji szczelin

| Id | Activity | Year | 
|----|----------|------| 
| 01 | AAAAA | 2008 | 
| 01 | AAAAA | 2009 | 
| 01 | AAAAA | 2010 | 
| 01 | AAAAA | 2012 | 
| 01 | AAAAA | 2013 | 
| 01 | AAAAA | 2015 | 
| 01 | BBBBB | 2014 | 
| 01 | BBBBB | 2015 | 

W rezultacie, która chciałaby wyglądać;

| 01 | AAAAA | 2008-2010, 2012-2013, 2015 | 
| 01 | BBBBB | 2014-2015     | 

Wszelkie pomysły na to, jak to osiągnąć, zostaną docenione.

Odpowiedz

6

Zastosowanie ROW_NUMBER do group the contiguous years i FOR XML PATH('') dla łańcuchów znaków.

SQL Fiddle

WITH Cte AS(
    SELECT *, 
     grp = year - ROW_NUMBER() OVER(PARTITION BY id, activity ORDER BY year) 
    FROM tbl 
) 
SELECT 
    id, 
    activity, 
    x.years 
FROM Cte c 
CROSS APPLY(
    SELECT STUFF((
     SELECT ', ' + CONVERT(VARCHAR(4), MIN(year)) + 
      CASE 
       WHEN MIN(year) <> MAX(year) THEN '-' + CONVERT(VARCHAR(4), MAX(year)) 
       ELSE '' 
      END 
     FROM Cte 
     WHERE 
      id = c.id 
      ANd activity = c.activity 
     GROUP BY id, activity, grp 
     FOR XML PATH('') 
    ), 1, 2, '') 
)x(years) 
GROUP BY id, activity, x.years 

WYNIK:

| id | activity |      years | 
|----|----------|----------------------------| 
| 01 | AAAAA | 2008-2010, 2012-2013, 2015 | 
| 01 | BBBBB |     2014-2015 | 
+1

niesamowite ......... – Utsav

+0

To jest niesamowite! Dziękuję Ci. – Baussie

+0

Cieszę się, że mogłem pomóc! –

1

Można to zrobić za pomocą ścieżki XML (dla złączenie wartości grupowych) i grupowanie przez id i anctivity: Konfiguracja

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 po komentarzach i zauważając dobrze do żądanego wyjścia:

jeśli chcesz również grupa Kolejna jak 2008-2009 to trzeba dodatkowe grupowanie (różnica roku i rangi w każdej grupie daje odrębną grupę zagnieżdżoną):

Zapytanie:

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 | 
+0

Zamknij, ale nie to, czego potrzebuję do wyniku. Potrzebuję lat zsekwencjonowanych pogrupowanych na lata 2008-2010, 2012-2013, 2015. – Baussie

+0

Och, przykro mi, że nie zauważyłem twojej dobrej pracy – jfun

+0

@Buussie pozwól mi tylko edytować i poprawić moją odpowiedź – jfun

0

Ponieważ jest to sql-2012 i zostały zmodyfikowane stanowisko Odpowiedź geniuszu @FelixPamittan użyciu CONCAT.

;WITH Cte AS(
    SELECT *, 
     grp = year - ROW_NUMBER() OVER(PARTITION BY id, activity ORDER BY year) 
    FROM #TEMP 
) 
SELECT DISTINCT 
    id, 
    activity, 
    (SELECT STUFF((SELECT ', ' + CONCAT(MIN(year), 
        CASE 
         WHEN MIN(year) <> MAX(year) THEN CONCAT('-', MAX(year)) 
         ELSE '' 
        END) 
     FROM Cte 
     WHERE 
      id = c.id 
      ANd activity = c.activity 
     GROUP BY id, activity, grp 
     FOR XML PATH('') 
    ), 1, 2, '')) AS YEARS 
FROM Cte c