将序列号转换为 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 工作表)