按条件计算物品

Joh*_*han 3 postgresql count

在用户可以在多个设备上安装移动应用程序副本的应用程序中,我想知道每个用户拥有多少个 iphone 和多少个 android 应用程序。

我尝试了一个查询,例如

gv2=> SELECT userid, 
       COUNT(ALL version_identifier LIKE '%ios%'), 
       COUNT(ALL version_identifier LIKE '%android%') 
FROM gl.user_device 
GROUP BY userid;
                userid                | count | count 
--------------------------------------+-------+-------
 46d0f5b7-42b0-4aad-9162-1390c32cb06e |     7 |     7
 5d519794-abfe-4863-82d4-6da33db7637b |     7 |     7
 a81cff6b-30f2-4b6e-a5bf-b1a933904473 |     1 |     1
 b65f0708-0cd1-11e7-878b-06fa189da46b |     4 |     4
 94b91b02-ff43-4a9a-b317-037fa2a347d3 |     1 |     1
 a4cacd98-1216-4801-b058-b28b8fa632a9 |     8 |     8
(6 rows)
Run Code Online (Sandbox Code Playgroud)

这显然是错误的。

例如

gv2=> SELECT userid FROM gl.user_device WHERE version_identifier LIKE '%ios%';
                userid                
--------------------------------------
 5d519794-abfe-4863-82d4-6da33db7637b
(1 row)
Run Code Online (Sandbox Code Playgroud)

万一我需要支持 Postgres 10.1,但最好也支持 9.5.10,因为我有一个旧的生产数据库仍然在那个版本上。

Erw*_*ter 5

在 Postgres 9.4或更高版本中使用现代聚合FILTER语法:

SELECT userid,
       COUNT(*) FILTER (WHERE version_identifier LIKE '%ios%') AS nr_ios,
       COUNT(*) FILTER (WHERE version_identifier LIKE '%android%') AS nr_android
FROM   gl.user_device
GROUP  BY userid;
Run Code Online (Sandbox Code Playgroud)

它更短,更清晰,速度更快。看:

但它仍然会导致对整个表进行顺序扫描。

如果...

  • 桌子很大,性能很重要,
  • 很大比例的行对这两个计数都没有贡献,
  • 并且您有一个匹配的索引 -version_identifier在您的情况下是一个三元组索引,请参阅:

...然后运行两个单独的查询来挖掘索引的全部潜力。在 a 中包含两个子查询的示例FULL OUTER JOIN使其成为 100% 等效的直接替换:

SELECT userid
     , COALESCE(nr_ios    , 0) AS nr_ios
     , COALESCE(nr_android, 0) AS nr_android
FROM  (
   SELECT userid, COUNT(*) AS nr_ios
   FROM   gl.user_device
   WHERE  version_identifier LIKE '%ios%'
   GROUP  BY 1
   ) i
FULL JOIN (
   SELECT userid, COUNT(*) AS nr_android
   FROM   gl.user_device
   WHERE  version_identifier LIKE '%android%'
   GROUP  BY 1
   ) a USING (userid);
Run Code Online (Sandbox Code Playgroud)

有关的: