我有一个网站的示例ID列表,格式为: 站点名称,样本编号,以使给定站点有n个样本编号。例如,数据可以是:
site1 | 1
site1 | 2
等到任意n。
使用以下作为类似示例,下面的数据将从最后一个选择语句中得到答案:
CREATE TABLE #SiteWithId(SiteId VARCHAR(50), SampleNumber INT)
INSERT INTO #SiteWithId
(
SiteId,
SampleNumber
)
values
( 'test', -- SiteId - varchar(50)
1 -- SampleNumber - int
),
('test',2),
('test',3),
('test',4),
('test',6),
('test',7)
SELECT * FROM #SiteWithId
DROP TABLE #SiteWithId
--the answer
SELECT 'test', '1-4,6-7'
请注意,缺少的项目会中断最终答案。
我知道我可以遍历C#中的数据集并创建这样的项目。但是没有人知道仅使用sql创建这样的值,这样我就可以为报告吐出所需的值了吗?我想我也可以在sql中做一个循环,但是我担心它是不可扩展的,因为那并不是sql真正要做的。
除了sql或c#中的循环之外,还有其他更好的方法吗?
答案 0 :(得分:5)
这是一种依赖于窗口函数的解决方案。记录的SampleNumber
与具有相同的ROW_NUMBER()
的记录组中的SiteName
之间的差异为您提供了它所属的组。然后,外部查询汇总每个组:
SELECT SiteName, CONCAT(MIN(SampleNumber), '-', MAX(SampleNumber)) SampleRange
FROM (
SELECT
SiteName,
SampleNumber,
ROW_NUMBER() OVER(PARTITION BY SiteName ORDER BY SampleNumber) rn
FROM mytable
) x
GROUP BY SiteName, (SampleNumber - rn)
样本数据:
SiteName | SampleNumber :------- | -----------: site1 | 1 site1 | 2 site1 | 3 site1 | 5 site1 | 6 site1 | 8 site1 | 9 site1 | 10
结果:
SiteName | SampleRange :------- | :---------- site1 | 1-3 site1 | 5-6 site1 | 8-10
如果要将每个站点的所有范围合并在一条记录中,则可以添加另一级别的聚合并使用STRING_AGG()
(自SQL Server 2017起可用):
SELECT SiteName, STRING_AGG(SampleRange,',') SampleRange
FROM (
SELECT SiteName, CONCAT(MIN(SampleNumber), '-', MAX(SampleNumber)) SampleRange
FROM (
SELECT
SiteName,
SampleNumber,
ROW_NUMBER() OVER(PARTITION BY SiteName ORDER BY SampleNumber) rn
FROM mytable
) x
GROUP BY SiteName, (SampleNumber - rn)
) y
GROUP BY SiteName
Demo :
SiteName | SampleRange :------- | :----------- site1 | 1-3,5-6,8-10