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
Producerar exakt önskat resultat.
Om du hanterar en array av varchar (varchar[]
casta det bara till int[]
, innan du fortsätter. Det verkar vara i helt laglig form för det:
years::int[]
Ersätt det inre undervalet med namnet på din källtabell i produktiv kod.
FROM (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
,(3, '{1990,1991,2007}')
) AS tbl(id, years)
->
FROM tbl
Eftersom vi har att göra med ett naturligt stigande tal (året) kan vi använda en genväg för att bilda grupper av på varandra följande år (som bildar ett intervall). Jag subtraherar själva året från radnummer (ordnat efter år). Under på varandra följande år ökar både radnummer och år med ett och producerar samma grp
siffra. Annars startar ett nytt sortiment.
Mer om fönsterfunktioner i manualen här och här .
En plpgsql-funktion kan vara ännu snabbare i det här fallet. Du måste testa. Exempel i dessa relaterade svar:
Beställt antal på varandra följande upprepningar/dubbletter
ROW_NUMBER() visar oväntade värden