SELECT id, string_agg(year_range, ', ') AS year_ranges
FROM (
SELECT id, CASE WHEN count(*) > 1
THEN min(year)::text || '-' || max(year)::text
ELSE min(year)::text
END AS year_range
FROM (
SELECT *, row_number() OVER (ORDER BY id, year) - year AS grp
FROM (
SELECT id, unnest(years) AS year
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
) sub1
) sub2
GROUP BY id, grp
ORDER BY id, min(year)
) sub3
GROUP BY id
ORDER BY id
Произвежда точно желания резултат.
Ако имате работа с масив от varchar (varchar[]
, просто го преобразувайте към int[]
, преди да продължите. Изглежда, че е в напълно законна форма за това:
years::int[]
Заменете вътрешния подизбор с името на вашата изходна таблица в продуктивен код.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Тъй като имаме работа с естествено нарастващо число (годината) можем да използваме пряк път, за да формираме групи от последователни години (формиране на диапазон). Изваждам самата година от номера на реда (подреден по година). За последователни години и номерът на ред, и годината се увеличават с едно и произвеждат един и същ grp
номер. В противен случай започва нов диапазон.
Повече за функциите на прозорците в ръководството тук и тук .
Функцията plpgsql може да бъде дори по-бърза в този случай. Трябва да тествате. Примери в тези свързани отговори:
Поръчан брой последователни повторения/дубликати
ROW_NUMBER() показва неочаквани стойности