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
Produce esattamente il risultato desiderato.
Se hai a che fare con un array di varchar (varchar[]
, lancialo su int[]
, prima di procedere. Sembra essere in forma perfettamente legale per questo:
years::int[]
Sostituisci la sottoselezione interna con il nome della tua tabella di origine nel codice produttivo.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Poiché abbiamo a che fare con un numero naturalmente crescente (l'anno) possiamo usare una scorciatoia per formare gruppi di anni consecutivi (formando un intervallo). Sottrai l'anno stesso dal numero di riga (ordinato per anno). Per anni consecutivi, sia il numero di riga che l'anno aumentano di uno e producono lo stesso grp
numero. Altrimenti, inizia una nuova gamma.
Ulteriori informazioni sulle funzioni della finestra nel manuale qui e qui .
Una funzione plpgsql potrebbe essere ancora più veloce in questo caso. Dovresti fare un test. Esempi in queste risposte correlate:
Conteggio ordinato di ripetizioni/duplicati consecutivi
ROW_NUMBER() mostra valori imprevisti