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
Producerer præcis det ønskede resultat.
Hvis du beskæftiger dig med en række varchar (varchar[]
, bare cast den til int[]
, før du fortsætter. Det ser ud til at være i fuldkommen lovlig form for det:
years::int[]
Erstat det indre undervalg med navnet på din kildetabel i produktiv kode.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Da vi har at gøre med et naturligt stigende tal (året) kan vi bruge en genvej til at danne grupper af på hinanden følgende år (danner et interval). Jeg trækker selve året fra rækkenummer (ordnet efter år). I på hinanden følgende år stiger både rækkenummer og år med én og producerer den samme grp
nummer. Ellers starter en ny serie.
Mere om vinduefunktioner i manualen her og her .
En plpgsql-funktion kan være endnu hurtigere i dette tilfælde. Du skulle teste. Eksempler i disse relaterede svar:
Bestilt antal på hinanden følgende gentagelser/duplikater
ROW_NUMBER() viser uventede værdier