简体   繁体   English

从年份列表中获取年份范围?

[英]Get list of year ranges from list of years?

Is it possible to get a list of year ranges from a list of years? 是否可以从年份列表中获得年份范围列表?

Say there is a table like 说有一张桌子

Year
1990
1991
1992
1999
2001
2002
2015

Or like 或喜欢

Years
1990,1991,1992,1999,2001,2002,2015

I am not sure where to start; 我不确定从哪里开始。 how can one get the ranges within those years? 在那几年内如何获得范围? eg 例如

1990-1992,1999,2001-2002,2015

Here is example: 这是示例:

SELECT *
INTO #years
FROM (VALUES 
(1990),
(1991),
(1992),
(1999),
(2001),
(2002),
(2015)) AS D(Year)

SELECT STUFF((
SELECT ',' +
    CASE 
        WHEN MIN(Year) = MAX(Year) THEN CAST(MIN(Year) AS VARCHAR(9))
        WHEN MIN(Year) <> MAX(Year) THEN CAST(MIN(Year) AS VARCHAR(4)) + '-' +CAST(MAX(Year) AS VARCHAR(4))
    END AS [text()]
FROM (
    SELECT Year
        ,Year-ROW_NUMBER() OVER (ORDER BY Year) AS rowID
    FROM #years) a
GROUP BY rowID
FOR XML PATH('')
),1,1,'');

The main idea is to find so called islands, which in this case is easy made by using ROW_NUMBER in this select: 主要思想是找到所谓的孤岛,在这种情况下,通过在此选择中使用ROW_NUMBER可以轻松实现:

SELECT Year ,Year-ROW_NUMBER() OVER (ORDER BY Year) 

Years will be subtracted from row numbers, which will mark same "islands". 行号将减去年份,这将标记相同的“岛”。 Meaning, if every next year are increasing by one as row number does, we will get same result number: 意思是,如果明年每隔行数增加一,我们将得到相同的结果数:

YEAR  RowNR RESULT  
1999  1     1998  
2000  2     1998  
2015  3     2012  

This result numbers can be later used for grouping and getting MAX and MIN values. 此结果编号以后可用于分组和获取MAX和MIN值。

The technique to get actual ranges is known as islands and gaps . 获得实际范围的技术称为孤岛和间隙 And to get values aggregated in one row you can use different techniques, but here's simple one with accumulating data in the variable will work fine. 为了将值汇总成一行,您可以使用不同的技术,但这是在变量中累积数据的简单方法,可以很好地工作。

declare @temp table (y int)
declare @res nvarchar(max)

insert into @temp (y)
values
    (1990),
    (1991),
    (1992),
    (1999),
    (2001),
    (2002),
    (2015)

;with cte_rn as (
    select
        row_number() over(order by y) as rn, y
    from @temp
), cte_rng as (
    select
        case
            when count(*) = 1 then cast(min(y) as nvarchar(max))
            else cast(min(y) as nvarchar(max)) + '-' + cast(max(y) as nvarchar(max))
        end as rng
    from cte_rn
    group by y - rn
)
select @res = isnull(@res + ', ', '') + rng
from cte_rng

sql fiddle demo sql小提琴演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM