特定の難しさ ここ:SELECTに1つ以上の集計関数があるクエリ リストがあり、GROUP BYはありません 句は、行が見つからない場合でも、正確に1つの行を生成します 基になるテーブルにあります。
WHEREでできることは何もありません その行を抑制する句。 事後にそのような行を除外する必要があります 、つまりHAVING 句、または外部クエリで。
ドキュメントごと:
クエリに集計関数呼び出しが含まれているが、
GROUP BYが含まれていない場合 句、グループ化は引き続き発生します。結果は単一のグループ行になります(または、単一の行がHAVINGによって削除された場合は、おそらくnorowsになります。 )。HAVINGが含まれている場合も同様です。 句、aggregatefunction呼び出しまたはGROUP BYがなくても 条項。
GROUP BYを追加することに注意してください。 定数式のみの句(それ以外の場合は完全に無意味です!)も機能します。 以下の例を参照してください。 しかし、それが何をするのかはほとんど明らかではないので、短く、安く、単純であっても、私はそのトリックを使用したくありません。
次のクエリには、単一テーブルスキャンのみが必要です。 カウント順に上位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を含めるには括弧が必要です またはORDER BYUNIONの個々のレッグへの句 クエリ。 -
テーブル
categoryに参加するだけです。 上位7つのカテゴリ。また、このシナリオでは、最初に集約して後で参加する方が一般的に安価です。したがって、cteという名前のCTE(共通テーブル式)の基本クエリに参加しないでください。 、最初のSELECTにのみ参加しますUNIONの クエリ、それは安いです。 -
COALESCEが必要な理由がわからない 。contents.categoryidの外部キーを使用している場合category.idへ および両方のcontents.categoryidおよびcategory.nameNOT NULLで定義されています (おそらくそうあるべきです)、それならあなたはそれを必要としません。
奇妙なGROUP BY true
これも機能します:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true; また、クエリプランが少し速くなります。しかし、それはかなり奇妙なハックです...
SQLフィドル すべてを示しています。
UNION ALLの詳細な説明を含む関連回答 / LIMIT テクニック:
- いくつかのクエリの結果を合計して、SQLで上位5つを見つけます