是否可以从年份列表中获取年份范围列表?
假设有一个类似
的表格Year
1990
1991
1992
1999
2001
2002
2015
或者喜欢
Years
1990,1991,1992,1999,2001,2002,2015
我不知道从哪里开始;如何在这些年内获得范围? e.g。
1990-1992,1999,2001-2002,2015
答案 0 :(得分:9)
以下是示例:
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,'');
主要想法是找到所谓的岛屿,在这种情况下,通过在此选择中使用ROW_NUMBER
可以轻松制作:
SELECT Year ,Year-ROW_NUMBER() OVER (ORDER BY Year)
将从行号中减去年份,这将标记相同的“岛屿”。这意味着,如果每隔一年按行数增加一个,我们将获得相同的结果编号:
YEAR RowNR RESULT
1999 1 1998
2000 2 1998
2015 3 2012
此结果编号稍后可用于分组并获取MAX和MIN值。
答案 1 :(得分:2)
获得实际范围的技术称为islands and gaps。要获得汇总在一行中的值,您可以使用不同的技术,但这里的简单数据在变量中累积数据将会正常工作。
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 强>