特定の難しさ ここ: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 BY
UNION
の個々のレッグへの句 クエリ。 -
テーブル
category
に参加するだけです。 上位7つのカテゴリ。また、このシナリオでは、最初に集約して後で参加する方が一般的に安価です。したがって、cte
という名前のCTE(共通テーブル式)の基本クエリに参加しないでください。 、最初のSELECT
にのみ参加しますUNION
の クエリ、それは安いです。 -
COALESCE
が必要な理由がわからない 。contents.categoryid
の外部キーを使用している場合category.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フィドル すべてを示しています。
UNION ALL
の詳細な説明を含む関連回答 / LIMIT
テクニック:
- いくつかのクエリの結果を合計して、SQLで上位5つを見つけます