在单个 SELECT 语句中返回多个范围的计数

Bry*_*yan 12 postgresql aggregate aggregate-filter

我有一个 Postgres 数据库表foo,其中有一个score范围为 0 - 10的列。我想要一个查询来返回分数总数、0 到 3 之间的分数数、4 之间的分数数和 6,以及 7 到 10 之间的分数。类似于以下内容:

SELECT
  COUNT(*) as total,
  COUNT(
    SELECT * from foo where score between 0 and 3;
  ) as low,
  COUNT(
    SELECT * from foo where score between 4 and 6;
  ) as mid,
  COUNT(
    SELECT * from foo where score between 7 and 10;
  ) as high
FROM foo;
Run Code Online (Sandbox Code Playgroud)

我试过这个,但SELECTCOUNT语句中出现错误。任何想法我怎么能做到这一点?我确定 Postgres 中有一个超级简单的方法。我只是想不出 Google 的正确术语。

Phi*_*lᵀᴹ 13

只需SUM()对每个数字范围使用每列的条件语句。SUM(1)假设表中的所有数据都在其中一个范围内,只需使用 就可以对总数进行求和- 如果不是,则像其他范围一样对其进行限制。

select sum(case when score between 0 and 3 then 1 else 0 end) as minrange,
       sum(case when score between 4 and 6 then 1 else 0 end) as midrange,
       sum(case when score between 7 and 10 then 1 else 0 end) as maxrange,
       sum(1) as total
from foo;
Run Code Online (Sandbox Code Playgroud)

SQL 小提琴链接


Erw*_*ter 13

FILTERPostgres 9.4+ 中的聚合子句

从 Postgres 9.4 开始,有一种干净且快速(SQL 标准)的方式:

SELECT count(*) FILTER (WHERE score BETWEEN 0 AND 3)  AS low
     , count(*) FILTER (WHERE score BETWEEN 4 AND 7)  AS mid
     , count(*) FILTER (WHERE score BETWEEN 8 AND 10) AS high
     , count(*)                                       AS total
FROM   foo;
Run Code Online (Sandbox Code Playgroud)

totallowmid和相加high,除非涉及 NULL 或其他值。

链接:

另请阅读以下内容。

Postgres 9.3-

有几种技术:

@Phil提供了一个带有CASE语句的通用替代方法(除了sum(1),这不是标准方式)。我喜欢使用较短的形式:

SELECT count(score BETWEEN 0 AND 3  OR NULL) AS low
     , count(score BETWEEN 4 AND 6  OR NULL) AS mid
     , count(score BETWEEN 7 AND 10 OR NULL) AS high
     , count(*)                              AS total
FROM   foo;
Run Code Online (Sandbox Code Playgroud)

如果您的值如您的问题中所定义(仅0-10可能),请进一步简化:

SELECT count(score < 4 OR NULL)             AS low
     , count(score BETWEEN 4 AND 6 OR NULL) AS mid
     , count(score > 6 OR NULL)             AS high
     , count(*)                             AS total
FROM   foo;
Run Code Online (Sandbox Code Playgroud)

短一点,快一点。

细微差别

细微的差别相比,sum()菲尔的回答

需要注意的是,除了 之外count,当没有选择任何行时,这些函数返回一个空值。特别是,sum没有行返回空值,而不是人们所期望的零,......

  • count(*) 标准方式,比sum(1). 同样,null vs. 0 适用。

这些查询中的任何一个(包括 Phil 的)都计算 的空值total。如果这是不可取的,请改用:

count(score) AS total_not_null
Run Code Online (Sandbox Code Playgroud)

db<>fiddle here
旧的sqlfiddle (pg 9.3)