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_id
、e.item_template_id
、またはe.used
)例では。
used
以降 タイプはboolean
です 、式e.used = true
e.used
だけに燃え尽きるノイズです 。
o.name
以降 定義されていませんUNIQUE NOT NULL
、GROUP 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()を呼び出す