web-dev-qa-db-ja.com

列の場合のSQLカウント

テーブル内のデータの出現回数をカウントする列を作成する最良の方法は何ですか?テーブルは1つの列でグループ化する必要があります。

私は見た

_SELECT
    sum(CASE WHEN question1 = 0 THEN 1 ELSE 0 END) AS ZERO,
    sum(CASE WHEN question1 = 1 THEN 1 ELSE 0 END) AS ONE,
    sum(CASE WHEN question1 = 2 THEN 1 ELSE 0 END) AS TWO,
    category
FROM reviews
    GROUP BY category
_

ここで、question1の値は0、1、または2のいずれかです。

count(CASE WHEN question1 = 0 THEN 1)を使用したバージョンも確認しました

ただし、question1の可能な値の数が増えると、これは書きにくくなります。このクエリを記述して、おそらくパフォーマンスを最適化する便利な方法はありますか?

PS。私のデータベースはPostgreSQLです

19
user3542327

Postgres 9.4では、新しい、よりクリーンな集約FILTERオプションがあります:

_SELECT category
     , count(*) FILTER (WHERE question1 = 0) AS zero
     , count(*) FILTER (WHERE question1 = 1) AS one
     , count(*) FILTER (WHERE question1 = 2) AS two
FROM   reviews
GROUP  BY 1;
_

新しいFILTER句の詳細:

必要に応じてshort

_SELECT category
     , count(question1 = 0 OR NULL) AS zero
     , count(question1 = 1 OR NULL) AS one
     , count(question1 = 2 OR NULL) AS two
FROM   reviews
GROUP  BY 1;
_

考えられるバリアントの概要:

適切なクロス集計クエリ

crosstab()は、最高のパフォーマンスをもたらし、オプションのリストが長いほど短くなります。

_SELECT * FROM crosstab(
     'SELECT category, question1, count(*)::int AS ct
      FROM   reviews
      GROUP  BY 1, 2
      ORDER  BY 1, 2'
   , 'VALUES (0), (1), (2)'
   ) AS ct (category text, zero int, one int, two int);
_

詳細な説明:

30

「私にとって」「最良の」方法は、次のようなクエリを記述することです。

SELECT
    category,
    question1,
    count(*)
FROM reviews
GROUP BY category, question1

次に、このデータを使用して、アプリケーションロジックでテーブルを描画します。

その他のオプションは、すべてのグループ化結果に1つのJSON列を使用することです。これは次のような結果になります:

category1 | {"zero": 1, "one": 3, "two": 5}
category2 | {"one": 7, "two": 4}

等々。

このオプションのクエリは、json_build_objectおよびjson_aggを使用して前のオプションから構築できます。このオプションの最良の点-事前に、可能なquestion1値の数を知る必要はありません。

1