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

Posted

技术标签:

【中文标题】将序列号转换为 SQL 中缺少值的单列【英文标题】:Convert sequential numbers into single column with missing values in SQL 【发布时间】:2019-03-27 22:02:01 【问题描述】:

我有一个网站的示例 ID 列表,格式如下: Sitename, Sample Number 使得给定站点有 n 个样本编号。例如,数据可能是:

site1 | 1
site1 | 2

等到任意 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'

请注意,缺少的项目会在最终答案中造成中断。

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

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

【问题讨论】:

不需要循环。这似乎是使用 Numbers/Tally 表(甚至是临时 Tally 表)的一项相当小的任务。但是,我不明白您的数据的结构。蜇伤?行?一些格式会有所帮助。 【参考方案1】:

这是一个依赖窗口函数的解决方案。记录的SampleNumber 与其在具有相同SiteName 的记录组中的ROW_NUMBER() 之间的差异为您提供了它所属的组。然后,外部查询聚合每个组:

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)

Demo on DB Fiddle

样本数据:

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

结果:

站点名称 |采样范围 :------- | :---------- 网站1 | 1-3 网站1 | 5-6 网站1 | 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

站点名称 |采样范围 :------- | :----------- 网站1 | 1-3,5-6,8-10

【讨论】:

以上是关于将序列号转换为 SQL 中缺少值的单列的主要内容,如果未能解决你的问题,请参考以下文章

将不同单元格中具有两个日期的数据集转换为系列或序列(Google 工作表)

防止对 DateTime 值的反序列化进行时区转换

jQuery序列化将所有空格转换为加号

在 Sql Server 中使用 Pivot/unpivot 将单行转换为单列

将时间序列数据集转换为监督学习数据集

将 0 和 1 的序列转换为打印样式的页面列表