2015-03-27 2 views
-1

Можно ли получить список летних диапазонов из списка лет?Получить список летних диапазонов из списка лет?

Say есть таблица, как

Year 
1990 
1991 
1992 
1999 
2001 
2002 
2015 

Или как

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

Я не уверен, с чего начать; как можно получить диапазоны в те годы? например

1990-1992,1999,2001-2002,2015 
+1

Да, это возможно. – Tom

+0

Спасибо ... обновил мой вопрос. – user3071284

+0

Почему downvote? Если что-то я должен избегать, это поможет узнать, что это такое. – user3071284

ответ

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.

+0

Хорошее решение, отлично работает –

+0

Я буду продвигать, если вы можете объяснить, как это работает: «STUFF» и «FOR XML PATH» отвлекают от умения фактического запроса, который получает диапазоны. –

+0

@DStanley STUFF и XML не отвлекают здесь, это механизмы, которые делают эту работу. Этот код генерирует список, разделенный запятыми. –

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

Смежные вопросы