sql >> Base de Datos >  >> RDS >> PostgreSQL

Devuelve una matriz de años como rangos de años

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

Produce exactamente el resultado deseado.

Si trata con una matriz de varchar (varchar[] , simplemente cámbielo a int[] , antes de continuar. Parece estar en forma perfectamente legal para eso:

years::int[]

Reemplace la subselección interna con el nombre de su tabla fuente en código productivo.

 FROM  (VALUES (2::int, '{1999,2000,2010,2011,2012}'::int[])
              ,(3,      '{1990,1991,2007}')
       ) AS tbl(id, years)

->

FROM  tbl

Ya que estamos tratando con un número naturalmente ascendente (el año) podemos usar un atajo para formar grupos de años consecutivos (formando un rango). Resto el año en sí del número de fila (ordenado por año). Para años consecutivos, tanto el número de fila como el año aumentan en uno y producen el mismo grp número. De lo contrario, comienza un nuevo rango.

Más sobre funciones de ventana en el manual aquí y aquí .

Una función plpgsql podría ser incluso más rápida en este caso. Tendrías que probar. Ejemplos en estas respuestas relacionadas:
Recuento ordenado de repeticiones/duplicados consecutivos
ROW_NUMBER() muestra valores inesperados