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
Produkuje dokładnie pożądany wynik.
Jeśli masz do czynienia z tablicą varchar (varchar[]
, po prostu prześlij go do int[]
, zanim przejdziesz dalej. Wydaje się, że jest to w pełni legalna forma:
years::int[]
Zastąp wewnętrzny podwybór nazwą tabeli źródłowej w produktywnym kodzie.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Ponieważ mamy do czynienia z liczbą naturalnie rosnącą (rok) możemy użyć skrótu, aby utworzyć grupy kolejnych lat (tworząc zakres). Od numeru wiersza odejmuję sam rok (uporządkowany według roku). W kolejnych latach zarówno numer wiersza, jak i rok zwiększają się o jeden i dają ten sam grp
numer. W przeciwnym razie zaczyna się nowy asortyment.
Więcej o funkcjach okien w instrukcji tutaj i tutaj .
W tym przypadku funkcja plpgsql może być jeszcze szybsza. Musiałbyś przetestować. Przykłady w tych powiązanych odpowiedziach:
Uporządkowana liczba kolejnych powtórzeń/duplikatów
ROW_NUMBER() pokazuje nieoczekiwane wartości