もつれを解き、単純化し、修正すると、次のようになります。
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<>ここでフィドル
すべてのノイズ、誤解を招く識別子、および型にはまらない形式の中で、実際の問題はここに隠されていました:
WHERE version = 1
RIGHT [OUTER] JOINを正しく使用しました 。ただし、WHEREを追加する mytableの既存の行を必要とする句 RIGHT [OUTER] JOINを変換します [INNER] JOINへ 効果的に。
そのフィルターをJOINに移動します それを機能させるための条件。
そこにいる間、私は他のいくつかのことを単純化しました。
より良い、それでも
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<>ここでフィドル
最初に集計して後で参加する方がはるかに安価です。1日1行ではなく、1か月に1行参加します。
GROUP BYをベースにする方が安価です およびORDER BY date レンダリングされたtextの代わりに値 。
count(*) count(id)より少し速いです 、 thisでは同等ですが クエリ。
generate_series() timestampに基づくと、少し速く安全になります dateの代わりに 。参照:
- PostgreSQLで2つの日付間の時系列を生成する