Ana*_*hah 3 sql-server user-defined-functions sql-server-2008 sql-server-2008-r2
我在MSSQL 2008R2中有一个表:
ID | PinAddress ------------------------------------- 1 | 1 1 | 2 1 | 3 1 | 4 1 | 5 1 | 6 1 | 16 1 | 31 2 | 55 2 | 56 2 | 57 2 | 81 2 | 82 2 | 83 2 | 84 3 | 101 3 | 102 3 | 103 3 | 107 3 | 108 3 | 109
我想要的是当我搜索ID = 1时,我想要结果如此
1-6,16,31
当我搜索ID = 2时,我想要结果
55-57,81-84
当我搜索ID = 3时,我想要结果
101-103,107-109
您可以使用以下脚本来创建表和数据:
CREATE TABLE PinAddress(ID INT,PinAddress INT)
INSERT INTO PinAddress values(1,1)
INSERT INTO PinAddress values(1,2)
INSERT INTO PinAddress values(1,3)
INSERT INTO PinAddress values(1,4)
INSERT INTO PinAddress values(1,5)
INSERT INTO PinAddress values(1,6)
INSERT INTO PinAddress values(1,16)
INSERT INTO PinAddress values(1,31)
INSERT INTO PinAddress values(2,55)
INSERT INTO PinAddress values(2,56)
INSERT INTO PinAddress values(2,57)
INSERT INTO PinAddress values(2,81)
INSERT INTO PinAddress values(2,82)
INSERT INTO PinAddress values(2,83)
INSERT INTO PinAddress values(2,84)
INSERT INTO PinAddress values(3,101)
INSERT INTO PinAddress values(3,102)
INSERT INTO PinAddress values(3,103)
INSERT INTO PinAddress values(3,107)
INSERT INTO PinAddress values(3,108)
INSERT INTO PinAddress values(3,109)
Run Code Online (Sandbox Code Playgroud)
谢谢
这是一个空白和岛屿问题,关键是确定你的连续范围,这是使用ROW_NUMBER().因此对于ID 3,您有:
ID PinAddress RowNumber
---------------------------
3 101 1
3 102 2
3 103 3
3 107 4
3 108 5
3 109 6
Run Code Online (Sandbox Code Playgroud)
从引脚地址中扣除行号将为每个连续范围提供一个常量值:
ID PinAddress RowNumber (PinAddress - RowNumber)
---------------------------------------------------
3 101 1 100
3 102 2 100
3 103 3 100
---------------------------------------------------
3 107 4 103
3 108 5 103
3 109 6 103
Run Code Online (Sandbox Code Playgroud)
到目前为止的查询很简单:
SELECT ID,
PinAddress,
GroupingSet = PinAddress - ROW_NUMBER() OVER(PARTITION BY ID ORDER BY PinAddress)
FROM dbo.PinAddress;
Run Code Online (Sandbox Code Playgroud)
然后,您可以按常量值和ID进行分组,并使用MIN和MAX获取每个范围的开始和结束:
WITH RankedData AS
( SELECT ID,
PinAddress,
GroupingSet = PinAddress - ROW_NUMBER() OVER(PARTITION BY ID ORDER BY PinAddress)
FROM PinAddress
)
SELECT ID,
RangeStart = MIN(PinAddress),
RangeEnd = MAX(PinAddress),
RangeText = CONVERT(VARCHAR(10), MIN(PinAddress)) +
CASE WHEN MIN(PinAddress) = MAX(PinAddress) THEN ''
ELSE ' - ' + CONVERT(VARCHAR(10), MAX(PinAddress))
END
FROM RankedData
GROUP BY ID, GroupingSet;
Run Code Online (Sandbox Code Playgroud)
其中,对于ID 3给出:
ID RangeStart RangeEnd RangeText
-----------------------------------------
3 101 103 101 - 103
3 107 109 107 - 109
Run Code Online (Sandbox Code Playgroud)
最后,您需要将RangeText值连接成一行,这可以使用SQL Server的XML Extensions完成.
WITH RankedData AS
( SELECT ID,
PinAddress,
GroupingSet = PinAddress - ROW_NUMBER() OVER(PARTITION BY ID ORDER BY PinAddress)
FROM PinAddress
)
SELECT p.ID,
Ranges = STUFF((SELECT ', ' + CONVERT(VARCHAR(10), MIN(PinAddress)) +
CASE WHEN MIN(PinAddress) = MAX(PinAddress) THEN ''
ELSE ' - ' + CONVERT(VARCHAR(10), MAX(PinAddress))
END
FROM RankedData AS rd
WHERE rd.ID = p.ID
GROUP BY ID, GroupingSet
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '')
FROM (SELECT DISTINCT ID FROM PinAddress) AS p;
Run Code Online (Sandbox Code Playgroud)
这使:
ID Ranges
------------------------------
1 1 - 6, 16 - 16, 31 - 31
2 55 - 57, 81 - 84
3 101 - 103, 107 - 109
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
704 次 |
| 最近记录: |