SQL Sequential Grouping和序列间隙的字符串

时间:2015-10-16 03:54:10

标签: sql sql-server sql-server-2012

我正在尝试使用SQL 2012基于以下数据生成特定字符串

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

结果需要看起来像;

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

非常感谢任何有关如何实现这一目标的想法。

3 个答案:

答案 0 :(得分:6)

使用ROW_NUMBERgroup the contiguous yearsFOR XML PATH('')进行字符串连接。

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

结果:

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

答案 1 :(得分:1)

您可以使用XML路径(用于连接组值)和按 id anctivity 进行分组:

MS SQL Server架构设置

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 )

<强>查询

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 |

在评论后进行编辑并注意到所需的输出:

如果您还希望将连续分组如 2008-2009 那么您需要额外的分组(每组中年份和等级的差异将为您提供一个独特的嵌套组):

<强>查询

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 |

答案 2 :(得分:0)

因为它的sql-2012我使用CONCAT修改了天才@FelixPamittan的答案帖子。

;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