sql >> データベース >  >> RDS >> PostgreSQL

generate_series()でカウントクエリに参加し、Null値を「0」として取得します

    もつれを解き、単純化し、修正すると、次のようになります。

    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つの日付間の時系列を生成する



    1. 数値の列値のみを取得するにはどうすればよいですか?

    2. Oracle:JMSメッセージを送信するJavaストアドプロシージャ

    3. SQL:UNIONを使用して、特定の選択で並べ替える方法は?

    4. SQLServerでスキーマバインドビューを作成する