我有一个numeric[]
个值的列,它们都具有相同的大小。我想采取他们的元素平均值。我的意思是平均值
{1, 2, 3}, {-1, -2, -3}, and {3, 3, 3}
应为{1, 1, 1}
。同样令人感兴趣的是如何对这些元素进行求和,尽管我希望任何一个解决方案都能成为另一个解决方案。
(注意:数组的长度在一个表中是固定的,但在表之间可能会有所不同。所以我需要一个不假定一定长度的解决方案。)
我最初的猜测是我应该以某种方式使用unnest
,因为应用于unnest
列的numeric[]
会使所有数组变平。因此,我想认为使用某种窗口函数+ group by
可以很好地使用它来挑选每个数组的各个组件并将它们相加。
-- EXAMPLE DATA
CREATE TABLE A
(vector numeric[])
;
INSERT INTO A
VALUES
('{1, 2, 3}'::numeric[])
,('{-1, -2, -3}'::numeric[])
,('{3, 3, 3}'::numeric[])
;
答案 0 :(得分:4)
我自己发现了一个解决方案,可能就是我将使用的解决方案。
首先,我们可以定义一个添加两个向量的函数:
CREATE OR REPLACE FUNCTION vec_add(arr1 numeric[], arr2 numeric[])
RETURNS numeric[] AS
$$
SELECT array_agg(result)
FROM (SELECT tuple.val1 + tuple.val2 AS result
FROM (SELECT UNNEST($1) AS val1
,UNNEST($2) AS val2
,generate_subscripts($1, 1) AS ix) tuple
ORDER BY ix) inn;
$$ LANGUAGE SQL IMMUTABLE STRICT;
和乘以常数的函数:
CREATE OR REPLACE FUNCTION vec_mult(arr numeric[], mul numeric)
RETURNS numeric[] AS
$$
SELECT array_agg(result)
FROM (SELECT val * $2 AS result
FROM (SELECT UNNEST($1) AS val
,generate_subscripts($1, 1) as ix) t
ORDER BY ix) inn;
$$ LANGUAGE SQL IMMUTABLE STRICT;
然后我们可以使用PostgreSQL语句CREATE AGGREGATE
直接创建vec_sum
函数:
CREATE AGGREGATE vec_sum(numeric[]) (
SFUNC = vec_add
,STYPE = numeric[]
);
最后,我们可以找到平均值:
SELECT vec_mult(vec_sum(vector), 1 / count(vector)) FROM A;
答案 1 :(得分:2)
我已经写了一个扩展来使用快速C函数进行向量加法(和减法,乘法,除法和幂)。您可以找到它on Github或PGXN。
鉴于两个数组a
和b
,您可以说vec_add(a, b)
。您还可以将任一侧添加到标量,例如vec_add(a, 5)
。
如果您想要SUM
聚合函数,则可以在aggs_for_vecs中找到该函数,也可以在PGXN上找到。
最后,如果您想总结单个数组的所有元素,可以使用aggs_for_arrays(PGXN)。
答案 2 :(得分:1)
来自http://www.postgresql.org/message-id/4C2504A3.4090502@wp.pl
select avg(unnested) from (select unnest(vector) as unnested from A) temp;
编辑:我想我现在更好地理解了这个问题。
以下是一个可能的解决方案:https://stackoverflow.com/a/8767450/3430807我不认为它优雅,也不确定它会表现良好:
测试数据:
CREATE TABLE A
(vector numeric[], id serial)
;
INSERT INTO A
VALUES
('{1, 2, 3}'::numeric[])
,('{4, 5, 6}'::numeric[])
,('{7, 8, 9}'::numeric[])
;
查询:
select avg(vector[temp.index])
from A as a
join
(select generate_subscripts(vector, 1) as index
, id
from A) as temp on temp.id = a.id
group by temp.index