PostgreSQL不同的行在一列中加入了不同值的计数

时间:2015-03-02 05:29:14

标签: 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;

但是,我很难将其与表格中的其他数据相结合。

最有效的方法是什么?

1 个答案:

答案 0 :(得分:3)

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

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

对于集成查询,我会采用稍微不同的方法(针对索引支持和模拟“松散索引扫描”):

SELECT t.*, a.z
FROM  (
   SELECT md5(a) AS md5_a, b, count(*) OVER (PARTITION BY a) AS z
   FROM   t
   GROUP  BY 1, 2
   ) a
, LATERAL (
   SELECT *
   FROM   t
   WHERE  md5(a) = a.md5_a
   AND    b = a.b
   ORDER  BY u, t
   LIMIT  1
  ) t
WHERE a.z > 2;

假设(缺少信息)您希望(u, t)上每组重复项的(a, b)行最小。

使用md5(a)代替a,因为a显然非常很长,并且您已经拥有md5(a)的索引等

count(*) OVER ...在单个查询级别中工作,因为在聚合之后应用了窗口函数:

由于您的表格是 big ,因此您需要有效的查询。这应该是最快的解决方案之一 - 具有足够的索引支持。 (md5(a), b)上的索引是有用的,但(md5(a), b, u, t)上的索引对于查询的第二步(横向连接)来说会更好。

详细解释(尤其是章节 2.JOIN LATERAL ):

有关更新的问题:(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;

我再次避免向GROUP BY大栏目(这将是昂贵的)。

关于DISTINCT ON