在单个查询中对单个表进行两次计数

Joh*_*han 6 postgresql

论坛上有一些类似的问题/答案,但我认为我的问题更简单。

我有两个问题,例如

SELECT count(*) FROM agent;
SELECT count(*) FROM agent WHERE active = 't';
Run Code Online (Sandbox Code Playgroud)

我希望输出在一行上。对于奖励积分,最好只扫描一次表格并更新两个计数器,以获得这样的结果

active_agents | total_agents
--------------+--------------
    10        |     20
Run Code Online (Sandbox Code Playgroud)

所以我想我有两个问题:
最简洁/最清晰的方法是什么,以及
对于非常大的表格,最快的方法是什么。

Aru*_*mar 6

您可以CASE在这种情况下使用语句:

SELECT count(*) AS total_agents, 
       SUM(CASE WHEN active = 't' THEN 1 ELSE 0 END) AS active_agents
FROM Agent;
Run Code Online (Sandbox Code Playgroud)

使用示例数据执行示例:

CREATE TABLE Agent (Id INT, Active CHAR(10));

INSERT INTO Agent (Active)
VALUES ('a'), ('b'), ('t'), ('c'), ('t'), ('d');

SELECT count(*) AS total_agents, 
       SUM(CASE WHEN active = 't' THEN 1 ELSE 0 END) AS active_agents
FROM Agent;
Run Code Online (Sandbox Code Playgroud)


Eva*_*oll 5

您可以通过其他几种方式做到这一点。除了 Arulkumar 的回答

样本数据

CREATE TEMP TABLE foo(x) AS
  VALUES (true),(false),(false),(true),(false);
Run Code Online (Sandbox Code Playgroud)

使用 FILTER

我更喜欢这种方法,因为它在语法上比该SUM()方法更简单,但两者的工作方式相同。

SELECT
  count(*)                  AS count_total,
  count(*) FILTER (WHERE x) AS count_where_x
FROM foo;
 count_total | count_where_x 
-------------+---------------
           5 |             2
(1 row)
Run Code Online (Sandbox Code Playgroud)

GROUP BY GROUPING SETS

如果你想要结果旋转,

EXPLAIN ANALYZE
SELECT x, count(*)
FROM foo
GROUP BY GROUPING SETS ((x),())
HAVING x IS TRUE
  OR x IS NULL;
 x | count 
---+-------
 t |     2   -- this is where x = true
   |     5   -- this is the total
(2 rows)
Run Code Online (Sandbox Code Playgroud)

或者,如果你真的想玩得开心..

HAVING x IS NOT false;
Run Code Online (Sandbox Code Playgroud)

因为这听起来很酷。