Sql 聚合函数,用于计算数组集合中的出现次数

Sql 聚合函数,用于计算数组集合中的出现次数,sql,postgresql,Sql,Postgresql,我有几个大型表,其中包含存储标识符数组的类似列。这些是分段标识符,表示行所属的分段 数据的简化版本可能如下所示: | score | segmentIds | |-------|------------| | 3 | [1, 2, 3] | | 22 | [3, 4, 5] | | 15 | [2, 4, 6] | 几种不同类型的查询需要知道聚合行相对于这些分段标识符的分布。这是通过计算在整数数组集中找到的每个标识符的出现次数来完成的。理想情况下,这可以通过保持在数组

我有几个大型表,其中包含存储标识符数组的类似列。这些是分段标识符,表示行所属的分段

数据的简化版本可能如下所示:

| score | segmentIds |
|-------|------------|
| 3     | [1, 2, 3]  |
| 22    | [3, 4, 5]  |
| 15    | [2, 4, 6]  |
几种不同类型的查询需要知道聚合行相对于这些分段标识符的分布。这是通过计算在整数数组集中找到的每个标识符的出现次数来完成的。理想情况下,这可以通过保持在数组中找到每个标识符的运行次数来实现

根据上述数据,获得分数的平均值和分段的分布,可能会得出以下结果:

avg(score): 13.333
distribution(segmentIds): {1: 1, 2: 2, 3: 2, 4: 2, 5: 1, 6: 1}
我已经编写了一个自定义聚合函数来实现这一点,但我希望能够找到一种更有效的方法(从时间和空间的角度)。最糟糕的情况是,它需要在几十万行上运行,其中每行将包含一行,该行在数组中包含大约10-30个标识符

CREATE TYPE array_union_type AS (
    a       int[],
    l       int
);

CREATE FUNCTION array_union_all(array_union_type, INT[], int) RETURNS array_union_type
AS $$
BEGIN
  RETURN ROW($1.a + $2, $3);
END;
$$ LANGUAGE PLPGSQL STRICT PARALLEL SAFE IMMUTABLE ;


CREATE FUNCTION array_union_combine(array_union_type, array_union_type) RETURNS array_union_type
AS $$
BEGIN
  RETURN ROW($1.a + $2.a, $1.l);
END;
$$ LANGUAGE PLPGSQL STRICT PARALLEL SAFE IMMUTABLE ;

CREATE FUNCTION array_count_final(array_union_type) RETURNS JSONB
AS $$ SELECT
    jsonb_object_agg(i, c)
FROM
    (
        SELECT
            i,
            COUNT(*) AS c
        FROM
            unnest($1.a) AS t(i)
        GROUP BY
            1) AS t
where
     c >= $1.l
$$ LANGUAGE SQL STRICT PARALLEL SAFE IMMUTABLE ;

CREATE aggregate array_count_agg(int[], int)
(
  SFUNC = array_union_all,
  STYPE = array_union_type,
  INITCOND = '({}, 0)',
  COMBINEFUNC = array_union_combine,
  FINALFUNC = array_count_final,
  PARALLEL = SAFE
);
我已经创建了自定义类型,因为我需要发送“limit”参数,这将最终丢弃在给定时间内发生的任何片段。这不是很漂亮,但从我所能发现的来看,不可能将额外的参数传递给最终的函数,所以这似乎是实现这一点的唯一方法

从CS的角度来看,数千次将数组连接在一起,然后计算出现次数并不理想。相反,在处理每一行时保持一个运行计数是很好的,但我不知道如何在PL/SQL中表示该状态


我应该注意,这需要在AWS RDS上的Postgres上运行,因此我们不能使用C函数。

我没有阅读您发布的所有内容,但您可能需要
distinct
,它只返回指定列的不同(不同)值/行。然后,您可以使用子查询计算该值的出现次数。请提供示例数据和所需结果。谢谢,我使用一些示例数据和所需结果进行了更新。您可以通过创建其他具有SegmentId+connectionId的表来规范表,该表在具有分数的表中应该是唯一的。那么,在sql Request中操作数据应该更容易,我们已经考虑过了,但这会使表变得非常大。表中还有许多其他数据段也是筛选和索引所必需的,这些数据段都必须复制。由于一行中的每个数组包含30-40个以上的元素,这将对应一个30倍大的表。它可以进一步规范化,但这会导致大量连接,从而降低性能。我不会阅读您发布的所有内容,但您可能需要
distinct
,它只返回指定列的不同(不同)值/行。然后,您可以使用子查询计算该值的出现次数。请提供示例数据和所需结果。谢谢,我使用一些示例数据和所需结果进行了更新。您可以通过创建其他具有SegmentId+connectionId的表来规范表,该表在具有分数的表中应该是唯一的。那么,在sql Request中操作数据应该更容易,我们已经考虑过了,但这会使表变得非常大。表中还有许多其他数据段也是筛选和索引所必需的,这些数据段都必须复制。由于一行中的每个数组包含30-40个以上的元素,这将对应一个30倍大的表。它可以进一步规范化,但这会导致大量连接,从而降低性能。