PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Schließen Sie sich einer Zählabfrage auf generate_series() an und rufen Sie Nullwerte als „0“ ab.

Entwirrt, vereinfacht und fixiert könnte es so aussehen:

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<>hier fummeln

Unter all dem Lärm, den irreführenden Kennungen und dem unkonventionellen Format war das eigentliche Problem hier verborgen:

WHERE version = 1

Sie haben RIGHT [OUTER] JOIN korrekt verwendet . Aber ein WHERE hinzufügen -Klausel, die eine vorhandene Zeile aus mytable erfordert konvertiert den RIGHT [OUTER] JOIN zu einem [INNER] JOIN effektiv.

Verschieben Sie diesen Filter in den JOIN Bedingung, damit es funktioniert.

Dabei habe ich einige andere Dinge vereinfacht.

Noch besser

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<>hier fummeln

Es ist viel billiger, zuerst zu aggregieren und später beizutreten – eine Reihe pro Monat statt einer Reihe pro Tag beizutreten.

Es ist billiger, auf GROUP BY zu basieren und ORDER BY am date Wert anstelle des gerenderten text .

count(*) ist etwas schneller als count(id) , während es in this äquivalent ist Abfrage.

generate_series() ist etwas schneller und sicherer, wenn es auf timestamp basiert statt date . Siehe:

  • Generieren von Zeitreihen zwischen zwei Daten in PostgreSQL