条件SQL计数

条件SQL计数,sql,postgresql,count,group-by,aggregate-filter,Sql,Postgresql,Count,Group By,Aggregate Filter,创建统计表中数据出现次数的列的最佳方法是什么?该表需要按一列分组? 我的数据库是PostgreSQL 我看到: 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, categ

创建统计表中数据出现次数的列的最佳方法是什么?该表需要按一列分组?
我的数据库是PostgreSQL

我看到:

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
其中
问题1
的值可以是0、1或2

我还看到了使用
count的一个版本(当问题1=0然后是1时的情况)

但是,随着
question1
的可能值数量的增加,编写此问题变得更加麻烦。是否有一种方便的方法来编写此查询,可能会优化性能?

对我来说,“最好”的方法是编写如下查询:

SELECT
    category,
    question1,
    count(*)
FROM reviews
GROUP BY category, question1
然后,我使用这些数据在应用程序逻辑中绘制一个表

另一个选项是对所有分组结果使用一个JSON列。这将导致如下结果:

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


您可以使用
json\u build\u object
json\u agg
从上一个选项生成此选项的查询。此选项的最佳选择-您不需要提前知道可能的
问题1
值的数量。

使用Postgres 9.4或更高版本中的聚合
过滤器
选项:

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;
过滤器
子句的详细信息:

如果您希望它简短:

可能的变体概述:

正确的交叉表查询
crosstab()
可产生最佳性能,并且对于较长的选项列表,它的长度更短:

SELECT * FROM crosstab(
     'SELECT category, question1, count(*) 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);
详细说明:


您的版本非常合理,但如果希望语法正确,则应该包含
结尾。另一种选择是Postgres的
交叉表功能。我不知道哪一个性能更好。对不起,忘了键入End为什么不按类别和问题1分组并按组计算行数?@GiorgiNakeuri OP希望问题1的每个值都有列名,那么您需要将结果转换为所需的结果。@Ram,啊哈,好的,我知道了。在MSSQL中,它将按类别和问题分组,然后旋转分组结果。
SELECT * FROM crosstab(
     'SELECT category, question1, count(*) 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);