从数字序列动态创建范围

Fel*_*yer 3 sql t-sql numeric-ranges sql-server-2008-r2

我有一个如下表:

+----+-----+-----+
| ID | GRP | NR  |
+----+-----+-----+
|  1 | 1   | 101 |
|  2 | 1   | 102 |
|  3 | 1   | 103 |
|  4 | 1   | 105 |
|  5 | 1-2 | 106 |
|  6 | 1-2 | 109 |
|  7 | 1-2 | 110 |
|  8 | 2   | 201 |
|  9 | 2   | 202 |
| 10 | 3   | 300 |
| 11 | 3   | 350 |
| 12 | 3   | 351 |
| 13 | 3   | 352 |
+----+-----+-----+
Run Code Online (Sandbox Code Playgroud)

我想创建一个视图,将该列表分组GRP并连接其中的值NR.是否有可能动态检测序列并将其缩短为范围?就像1, 2, 3, 5会成为1-3, 5.

所以结果应该是这样的:

+-----+--------------------+
| GRP |        NRS         |
+-----+--------------------+
| 1   | 101 - 103, 105     |
| 1-2 | 106, 109 - 110     |
| 2   | 201 - 202          |
| 3   | 300, 350 - 352     |
+-----+--------------------+
Run Code Online (Sandbox Code Playgroud)

我现在得到的只是连接值,所以上面的表将成为这样:

+-----+--------------------+
| GRP |        NRS         |
+-----+--------------------+
| 1   | 101, 102, 103, 105 |
| 1-2 | 106, 109, 110      |
| 2   | 201, 202           |
| 3   | 300, 350, 351, 352 |
+-----+--------------------+
Run Code Online (Sandbox Code Playgroud)

这是实际的陈述:

DECLARE @T TABLE
(
    ID INT IDENTITY(1, 1)
  , GRP VARCHAR(10)
  , NR INT
)
INSERT INTO @T
VALUES ('1',101),('1',102),('1',103),('1',105)
      ,('1-2',106),('1-2',109), ('1-2',110)
      ,('2',201),('2',202)
      ,('3',300),('3',350),('3',351),('3',352)

SELECT * FROM @T

;WITH GROUPNUMS (RN, GRP, NR, NRS) AS 
(
    SELECT 1, GRP, MIN(NR), CAST(MIN(NR) AS VARCHAR(MAX)) 
    FROM @T
    GROUP BY GRP

    UNION ALL

    SELECT CT.RN + 1, T.GRP, T.NR, CT.NRS + ', ' + CAST(T.NR AS VARCHAR(MAX))
    FROM @T T
    INNER JOIN GROUPNUMS CT ON CT.GRP = T.GRP 
    WHERE T.NR > CT.NR
)
SELECT NRS.GRP, NRS.NRS
FROM GROUPNUMS NRS
INNER JOIN (
    SELECT GRP, MAX(RN) AS MRN 
    FROM GROUPNUMS 
    GROUP BY GRP
) R
ON NRS.RN = R.MRN AND NRS.GRP = R.GRP
ORDER BY NRS.GRP
Run Code Online (Sandbox Code Playgroud)

任何人都可以告诉我,是否很容易做到这样的事情?如果有人有想法并希望分享它会很棒.

val*_*lex 6

SQLFiddle演示

with TRes 
as 
(
select T.GRP,T.NR NR,
CASE WHEN T1.NR IS NULL and T2.NR is null
      THEN CAST(T.NR as VARCHAR(MAX))
     WHEN T1.NR IS NULL and T2.NR IS NOT NULL
      THEN '-'+CAST(T.NR as VARCHAR(MAX))
     WHEN T1.NR IS NOT NULL and T2.NR IS NULL
      THEN CAST(T.NR as VARCHAR(MAX))+'-'
END AS NR_GRP


from T
left join T T1 on T.Grp=T1.Grp and t.Nr+1=t1.Nr
left join T T2 on T.Grp=T2.Grp and t.Nr-1=t2.Nr

WHERE T1.NR IS NULL or T2.NR IS NULL

)
SELECT
   GRP,
   REPLACE(
   substring((SELECT ( ',' + NR_GRP)
                           FROM TRes t2
                           WHERE t1.GRP = t2.GRP
                           ORDER BY 
                              GRP,
                              NR
                           FOR XML PATH( '' )
                          ), 2, 10000 )
   ,'-,-','-')  
FROM TRes t1
GROUP BY GRP
Run Code Online (Sandbox Code Playgroud)