もつれを解き、単純化し、修正すると、次のようになります。
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つの日付間の時系列を生成する