ここでの具体的な問題SELECT
:リストに 1 つ以上の集計関数があり、GROUP BY
句がないクエリでは、基になるテーブルに行が見つからない場合でも、1 つの行が生成されます。
WHERE
その行を抑制するために句でできることは何もありません。そのような行は、事後、つまりHAVING
句内、または外部クエリで除外する必要があります。
ドキュメントごと:
クエリに集約関数の呼び出しが含まれていてもGROUP BY
句がない場合でも、グループ化は行われます。結果は単一のグループ行になります (または、単一の行が によって削除された場合は、行がまったくない可能性がありますHAVING
)。HAVING
集計関数の呼び出しや句がなくても、句が含まれている場合も同様ですGROUP BY
。
GROUP BY
定数式のみを含む節を追加すること (それ以外の場合は完全に無意味です!) も機能することに注意してください。以下の例を参照してください。しかし、たとえそれが短く、安価で、単純であっても、私はむしろそのトリックを使用したくありません。
次のクエリは、1 回のテーブル スキャンのみを必要とし、カウント順に並べられた上位 7 つのカテゴリを返します。さらにカテゴリがある場合 (およびその場合のみ)、残りは「その他」にまとめられます。
WITH cte AS (
SELECT categoryid, count(*) AS data
, row_number() OVER (ORDER BY count(*) DESC, categoryid) AS rn
FROM contents
GROUP BY 1
)
( -- parentheses required again
SELECT categoryid, COALESCE(ca.name, 'Unknown') AS label, data
FROM cte
LEFT JOIN category ca ON ca.id = cte.categoryid
WHERE rn <= 7
ORDER BY rn
)
UNION ALL
SELECT NULL, 'Others', sum(data)
FROM cte
WHERE rn > 7 -- only take the rest
HAVING count(*) > 0; -- only if there actually is a rest
-- or: HAVING sum(data) > 0
7 位 / 8 位で複数のカテゴリが同じ数になる場合は、タイを破る必要があります。私の例では、小さいカテゴリがそのcategoryid
ような競争に勝ちます。
LIMIT
or句をクエリORDER BY
の個々のレッグに含めるには、括弧が必要です。UNION
category
上位 7 カテゴリのテーブルに参加するだけです。また、このシナリオでは、最初に集約し、後で結合する方が一般的に安価です。したがって、という名前のCTE (共通テーブル式)cte
のベース クエリに参加しないでください。最初SELECT
のUNION
クエリにのみ参加してください。これは安価です。
が必要な理由がわかりませんCOALESCE
。fromとcontents.categoryid
tocategory.id
の両方が定義されている(おそらくそうあるべきであるように) 適切な場所に外部キーがある場合、それは必要ありません。contents.categoryid
category.name
NOT NULL
奇妙なGROUP BY true
これもうまくいきます:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true;
また、わずかに高速なクエリ プランも得られます。しかし、それはかなり奇妙なハックです...
すべてを示すSQL Fiddle 。
UNION ALL
/LIMIT
テクニックの詳細な説明を含む関連回答: