PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Retorna a matriz de anos como intervalos de anos

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

Produz exatamente o resultado desejado.

Se você lida com um array de varchar (varchar[] , basta convertê-lo para int[] , antes de prosseguir. Parece estar em forma perfeitamente legal para isso:
years::int[]

Substitua a sub-seleção interna pelo nome da sua tabela de origem no código produtivo.
 FROM  (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
              ,(3,      '{1990,1991,2007}')
       ) AS tbl(id, years)

->
FROM  tbl

Como estamos lidando com um número naturalmente crescente (o ano) podemos usar um atalho para formar grupos de anos consecutivos (formando um intervalo). Eu subtraio o próprio ano do número da linha (ordenado por ano). Para anos consecutivos, o número da linha e o ano são incrementados em um e produzem o mesmo grp número. Caso contrário, um novo intervalo é iniciado.

Mais sobre funções da janela no manual aqui e aqui .

Uma função plpgsql pode ser ainda mais rápida neste caso. Você teria que testar. Exemplos nestas respostas relacionadas:
Contagem ordenada de repetições/duplicatas consecutivas
ROW_NUMBER() mostra valores inesperados