sql - PostgreSQL 不同的行与一列中的不同值的计数连接

标签 sql postgresql count distinct aggregate-functions

我使用的是 PostgreSQL 9.4,我有一个 1300 万行的表,数据大致如下:

  a  | b | u  | t 
-----+---+----+----
 foo | 1 |  1 | 10
 foo | 1 |  2 | 11
 foo | 1 |  2 | 11
 foo | 2 |  4 | 1
 foo | 3 |  5 | 2
 bar | 1 |  6 | 2
 bar | 2 |  7 | 2
 bar | 2 |  8 | 3
 bar | 3 |  9 | 4
 bar | 4 | 10 | 5
 bar | 5 | 11 | 6
 baz | 1 | 12 | 1
 baz | 1 | 13 | 2
 baz | 1 | 13 | 2
 baz | 1 | 13 | 3

md5(a)b(md5(a), b) 上都有索引。 (实际上,a 可能包含超过 4k 个字符的值。)还有一个我在上面省略的 SERIAL 类型的主键列。

我正在尝试构建一个将返回以下结果的查询:

  a  | b | u  | t  | z 
-----+---+----+----+---
 foo | 1 |  1 | 10 | 3
 foo | 1 |  2 | 11 | 3
 foo | 2 |  4 | 1  | 3
 foo | 3 |  5 | 2  | 3
 bar | 1 |  6 | 2  | 5
 bar | 2 |  7 | 2  | 5
 bar | 2 |  8 | 3  | 5
 bar | 3 |  9 | 4  | 5
 bar | 4 | 10 | 5  | 5
 bar | 5 | 11 | 6  | 5

在这些结果中,所有行都被删除了重复项,就像应用了 GROUP BY a, b, u, t 一样,z 的不同值的计数b 用于 a 上的每个分区,并且仅包含 z 值大于 2 的行。

我可以让 z 过滤器按如下方式工作:

SELECT a, COUNT(b) AS z from (SELECT DISTINCT a, b FROM t) AS foo GROUP BY a
  HAVING COUNT(b) > 2;

但是,我很难将其与表中的其余数据结合起来。

执行此操作最有效的方法是什么?

最佳答案

您的第一步已经可以更简单了:

SELECT md5(a) AS md5_a, count(DISTINCT b) AS z
FROM   t
GROUP  BY 1
HAVING count(DISTINCT b) > 2;

使用 md5(a) 代替 a,因为 a 显然可以非常长,并且您已经有了关于 md5(a) 等的索引。

由于您的表很大,您需要一个高效的查询。这应该是最快的解决方案之一 - 具有足够的索引支持。您在 (md5(a), b) 上的索引是有用的,但是 - 假设 but是小列 - (md5(a), b, u, t) 上的索引对于查询的第二步(横向连接)会更好。

您想要的最终结果:

SELECT DISTINCT ON (md5(t.a), b, u, t)
       t.a, t.b, t.u, t.t, a.z
FROM  (
   SELECT md5(a) AS md5_a, count(DISTINCT b) AS z
   FROM   t
   GROUP  BY 1
   HAVING count(DISTINCT b) > 2
   ) a
JOIN   t ON md5(t.a) = md5_a
ORDER  BY 1, 2, 3, 4;  -- optional

或者可能更快,但是:

SELECT a, b, u, t, z
FROM  (
   SELECT DISTINCT ON (1, 2, 3, 4)
          md5(t.a) AS md5_a, t.b, t.u, t.t, t.a
   FROM   t
   ) t
JOIN  (
   SELECT md5(a) AS md5_a, count(DISTINCT b) AS z
   FROM   t
   GROUP  BY 1
   HAVING count(DISTINCT b) > 2
   ) z USING (md5_a)
ORDER  BY 1, 2, 3, 4;  -- optional

DISTINCT ON的详细解释:

关于sql - PostgreSQL 不同的行与一列中的不同值的计数连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28803208/

相关文章:

sql - Postgres 中同月的总和值

python-3.x - 使用@post_dump 通过 Marshmallow 添加总行数?

hibernate - 如何为热/暖备用 Postgresql 服务器配置 c3p0?

mysql - 在文件名sql表达式上将字符与日期分开

mysql - MYSQL 中 SUM 函数的索引

sql - 如何存储从 2017-08-20 到 2017-08-24 发生的事件?什么数据类型?

sql - 计算出重叠 er 数据库中的总人数

postgresql - postgresql sql shell命令中不同服务器之间的切换

string - 是否有返回两个字符串之间差异计数的函数?

track_total_hits 设置为 true 的 ElasticSearch Count API 与 SearchAPI