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

LEFT JOINを使用してクエリを実行すると、カウントが0の行が返されません。

    LEFT JOINを修正します

    これは機能するはずです:

    SELECT o.name AS organisation_name, count(e.id) AS total_used
    FROM   organisations   o
    LEFT   JOIN exam_items e ON e.organisation_id = o.id 
                            AND e.item_template_id = #{sanitize(item_template_id)}
                            AND e.used
    GROUP  BY o.name
    ORDER  BY o.name;
    

    LEFT [OUTER] JOINがありました しかし、後のWHERE 条件により、単純な[INNER] JOINのように動作しました 。
    条件をJOINに移動します 意図したとおりに機能させるための句。このようにして、最初にこれらすべての条件を満たす行(またはの列)のみが結合されます。 テーブルはNULLで埋められます)。あなたがそれを持っていたように、結合された行は事実上に追加の条件についてテストされます LEFT JOIN プレーンなJOINの場合と同様に、合格しなかった場合は削除されます 。

    count() そもそもNULLを返すことはありません。この点では、集計関数の例外です。したがって、 COALESCE(COUNT(col)) 決して 追加のパラメータがあっても、理にかなっています。マニュアル:

    countを除くことに注意してください 、行が選択されていない場合、これらの関数はnull値を返します。

    大胆な強調鉱山。参照:

    • 行に対してNULLである属性の数を数えます

    count() NOT NULLで定義された列に存在する必要があります (e.idのように )、または結合条件がNOT NULLを保証する場合 (e.organisation_ide.item_template_id 、またはe.used )例では。

    used以降 タイプはbooleanです 、式e.used = true e.usedだけに燃え尽きるノイズです 。

    o.name以降 定義されていませんUNIQUE NOT NULLGROUP BY o.idが必要な場合があります 代わりに(id PKであること)-意図しない 同じ名前(NULLを含む)の行を折りたたむ。

    最初に集約し、後で参加する

    exam_itemsのほとんどまたはすべての行の場合 プロセスでカウントされる場合、この同等のクエリは通常、かなり高速/安価です:

    SELECT o.id, o.name AS organisation_name, e.total_used
    FROM   organisations o
    LEFT   JOIN (
       SELECT organisation_id AS id   -- alias to simplify join syntax
            , count(*) AS total_used  -- count(*) = fastest to count all
       FROM   exam_items
       WHERE  item_template_id = #{sanitize(item_template_id)}
       AND    used
       GROUP  BY 1
       ) e USING (id)
    ORDER  BY o.name, o.id;
    

    (これは、上記のような同じ名前の行を折りたたまないことを前提としています-一般的なケースです。)

    これで、より高速でシンプルなcount(*)を使用できるようになりました。 サブクエリで、GROUP BYは必要ありません 外側のSELECT

    参照:

    • 1回のクエリで複数のarray_agg()を呼び出す


    1. SQLServerでのデータ圧縮の概要

    2. MariaDBでのSQRT()のしくみ

    3. データを別のテーブルにコピーする

    4. MySQLでのTO_BASE64()関数のしくみ