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

Únase a una consulta de conteo en generate_series() y recupere valores nulos como '0'

Desenredado, simplificado y arreglado, podría verse así:

SELECT to_char(s.tag,'yyyy-mm') AS monat
     , count(t.id) AS eintraege
FROM  (
   SELECT generate_series(min(date_from)::date
                        , max(date_from)::date
                        , interval '1 day'
          )::date AS tag
   FROM   mytable t
   ) s
LEFT   JOIN mytable t ON t.date_from::date = s.tag AND t.version = 1   
GROUP  BY 1
ORDER  BY 1;

db<>violín aquí

Entre todo el ruido, los identificadores engañosos y el formato poco convencional, el problema real estaba oculto aquí:

WHERE version = 1

Hiciste un uso correcto de RIGHT [OUTER] JOIN . Pero agregando un WHERE cláusula que requiere una fila existente de mytable convierte RIGHT [OUTER] JOIN a un [INNER] JOIN efectivamente.

Mueve ese filtro a JOIN condición para que funcione.

Simplifiqué algunas otras cosas mientras estaba en ello.

Mejor, aún

SELECT to_char(mon, 'yyyy-mm') AS monat
     , COALESCE(t.ct, 0) AS eintraege
FROM  (
   SELECT date_trunc('month', date_from)::date AS mon
        , count(*) AS ct
   FROM   mytable
   WHERE  version = 1     
   GROUP  BY 1
   ) t
RIGHT JOIN (
   SELECT generate_series(date_trunc('month', min(date_from))
                        , max(date_from)
                        , interval '1 mon')::date
   FROM   mytable
   ) m(mon) USING (mon)
ORDER  BY mon;

db<>violín aquí

Es mucho más económico agregar primero y unirse después:unirse a una fila por mes en lugar de una fila por día.

Es más barato basar GROUP BY y ORDER BY en la date valor en lugar del text representado .

count(*) es un poco más rápido que count(id) , mientras que es equivalente en este consulta.

generate_series() es un poco más rápido y seguro cuando se basa en timestamp en lugar de date . Ver:

  • Generando series de tiempo entre dos fechas en PostgreSQL