1

给定表格

| userid | active | anonymous |
|   1    |   t    |    f      |
|   2    |   f    |    f      |
|   3    |   f    |    t      |

我需要得到:

  • 用户数
  • 'active' = true 的用户数
  • “活跃”的用户数 = false
  • “匿名”的用户数 = true
  • “匿名”的用户数 = false

与单个查询。

至于现在,我只提出了使用union的解决方案:

SELECT count(*) FROM mytable
UNION ALL
SELECT count(*) FROM mytable where active
UNION ALL
SELECT count(*) FROM mytable where anonymous

所以我可以取第一个数字并通过简单的扣除找到非活跃和非匿名用户。

有什么方法可以摆脱联合并计算与这些简单条件匹配的记录数,并在PostgreSQL 9中使用一些神奇而高效的查询?

4

2 回答 2

3

您可以使用带有 a 的聚合函数CASE在单独的列中获取结果:

select 
  count(*) TotalUsers,
  sum(case when active = 't' then 1 else 0 end) TotalActiveTrue,
  sum(case when active = 'f' then 1 else 0 end) TotalActiveFalse,
  sum(case when anonymous = 't' then 1 else 0 end) TotalAnonTrue,
  sum(case when anonymous = 'f' then 1 else 0 end) TotalAnonFalse
from mytable;

请参阅带有演示的 SQL Fiddle

于 2013-04-23T00:39:08.070 回答
2

假设您的列是boolean NOT NULL,这应该会快一点:

SELECT total_ct
      ,active_ct
      ,(total_ct - active_ct) AS not_active_ct
      ,anon_ct
      ,(total_ct - anon_ct) AS not_anon_ct
FROM  (
   SELECT count(*) AS total_ct
         ,count(active OR NULL) AS active_ct
         ,count(anonymous OR NULL) AS anon_ct
   FROM  tbl
   ) sub;

查找此密切相关答案中使用的技术的详细说明:
Compute percents from SUM() in the same SELECT sql query

索引几乎没有任何用处,因为无论如何都必须读取整个表。如果您的行比示例中的大,覆盖索引可能会有所帮助。取决于您的实际表的具体情况。

-> SQLfiddle@bluefeet 的版本比较,每个值都有CASE语句

SQL 服务器的人不习惯正确boolean类型的 Postgres,并且倾向于走很长的路。

于 2013-04-23T01:59:16.193 回答