将序号转换为SQL中缺少值的单列

don*_*son 1 sql t-sql sql-server

我有一个网站的样本ID列表,格式为:站点名称,样本编号,这样一个给定站点的样本编号为n。例如,数据可以是:

site1 | 1
site1 | 2
Run Code Online (Sandbox Code Playgroud)

等到任意n

使用以下示例作为类似示例,下面的数据将从最后一个select语句中得到答案:

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'
Run Code Online (Sandbox Code Playgroud)

请注意,缺少的项目会导致最终答案中断。

我知道我可以遍历C#中的数据集并创建这样的项目。但是没有人知道仅使用sql创建这样的值,这样我就可以为报告吐出所需的值了吗?我想我也可以在sql中做一个循环,但是我担心它是不可伸缩的,因为那并不是sql真正要做的。

除了sql或c#中的循环之外,还有其他更好的方法吗?

GMB*_*GMB 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)
Run Code Online (Sandbox Code Playgroud)

DB Fiddle上的演示

样本数据:

网站名称| 样品编号
:------- | -----------:
site1 | 1个
site1 | 2
site1 | 3
site1 | 5
site1 | 6
site1 | 8
site1 | 9
site1 | 10

结果:

网站名称| 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
Run Code Online (Sandbox Code Playgroud)

演示

网站名称| SampleRange
:------- | :-----------
site1 | 1-3,5-6,8-10