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
Produceert precies het gewenste resultaat.
Als je te maken hebt met een array van varchar (varchar[]
, cast het gewoon naar int[]
, voordat u verder gaat. Het lijkt daarvoor in volkomen legale vorm te zijn:
years::int[]
Vervang de innerlijke subselectie door de naam van uw brontabel in productieve code.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Aangezien we te maken hebben met een natuurlijk oplopend getal (het jaar) kunnen we een snelkoppeling gebruiken om groepen van opeenvolgende jaren te vormen (een bereik vormen). Ik trek het jaar zelf af van het rijnummer (geordend op jaar). Voor opeenvolgende jaren worden zowel het rijnummer als het jaar met één verhoogd en produceren dezelfde grp
nummer. Anders begint er een nieuw assortiment.
Meer over vensterfuncties in de handleiding hier en hier .
Een plpgsql-functie is in dit geval misschien nog sneller. Je zou moeten testen. Voorbeelden in deze gerelateerde antwoorden:
Geordende telling van opeenvolgende herhalingen / duplicaten
ROW_NUMBER() toont onverwachte waarden