sql >> Databasteknik >  >> RDS >> PostgreSQL

Returnera array av år som årsintervall

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



  1. MySQL C++ Connector får en sträng med SELECT-fråga

  2. DeprecationWarning:Ett booleskt värde skickades till options.operatorsAliases. Detta är en no-op med v5 och bör tas bort

  3. Infoga Data mysql med Ajax och PHP

  4. Kalender i Zend Framework