在SQL Server中按多个范围分组

时间:2017-06-22 08:13:57

标签: sql sql-server group-by

我试图寻找解决方案,但没有成功。 如何将表格分组,如下所示:

from    |    to    |    zone
1       |    1     |      1
1       |    2     |      1
1       |    3     |      1
1       |    4     |      2
1       |    5     |      2
1       |    6     |      2
1       |    7     |      1
1       |    8     |      1
1       |    9     |      1
1       |    10    |      9
2       |    1     |      7
2       |    2     |      7
2       |    3     |      7
2       |    4     |      2
2       |    5     |      2
2       |    6     |      2
2       |    7     |      7
2       |    8     |      7
2       |    9     |      7

看起来像这样:

from    |    to      |    zone
1       |    1-3     |      1
1       |    4-6     |      2
1       |    7-9     |      1
1       |     10     |      9
2       |    1-3     |      7
2       |    4-6     |      2
2       |    7-9     |      7

感谢您的帮助

3 个答案:

答案 0 :(得分:2)

这里的一种方法是使用行号方法的差异,使用to列作为一个行号,使用fromzone作为分区上的行号其他行号。有一点难以解释为什么这么多用词。最好查看下面的演示链接来探索查询。

WITH cte AS (
    SELECT *,
       ROW_NUMBER() OVER (PARTITION BY [from], zone ORDER BY [to]) rn
    FROM yourTable
)
SELECT
    t.[from],
    CONVERT(varchar(10), MIN(t.[to])) + '-' + CONVERT(varchar(10), MAX([to])) AS [to],
    t.zone
FROM cte t
GROUP BY
    t.[from],
    t.zone,
    t.[to] - t.rn
ORDER BY
    t.[from],
    MIN(t.[to]);

在这里演示:

Rextester

答案 1 :(得分:1)

这通常被称为 Gaps and Islands 问题。如果您使用的是SQL Server 2012+,那么

;WITH cte
     AS (SELECT *,
                Sum(CASE WHEN zone = prev_zone THEN 0 ELSE 1 END)OVER(partition BY [from] ORDER BY [to]) AS grp
         FROM   (SELECT *,
                        Lag(zone)OVER(partition BY [from] ORDER BY [to]) AS prev_zone
                 FROM   yourtable ) cs ([from], [to], zone)) a)
SELECT [from],
       [to] = Concat(Min([to]), '-', Max([to])),
       zone = Min(zone) 
FROM   cte
GROUP  BY [from],grp

答案 2 :(得分:0)

;with mycte
AS
(
select
    ,[from]
    ,min([to]) minto
    ,max([to]) maxto
    ,[zone]
from
    mytable
group by
    [from]
    ,[zone]
)
    [from]                      AS [from]
    ,concat(minto, '-', maxto)  AS [to]
    ,[zone]                     AS [zone]
from
    mycte