在数组上聚合函数

f.a*_*uri 14 arrays postgresql aggregate-functions

我有这样一张桌子:

+-----+----------------+
| ID  |  array300      |
+-----+----------------+
| 100 | {110,25,53,..} |
| 101 | {56,75,59,...} |
| 102 | {65,93,82,...} |
| 103 | {75,70,80,...} |
+-----+----------------+

array300列是一个包含300个元素的数组.我需要有100个元素的数组,每个元素代表array300的3个元素的平均值.对于这个例子,答案将是:
array100
{62.66,...}
{63.33,...}
{80,...}
{78.33,...}

Igo*_*nko 11

尝试这样的事情:

SELECT id, unnest(array300) as val, ntile(100) OVER (PARTITION BY id) as bucket_num
FROM your_table
Run Code Online (Sandbox Code Playgroud)

SELECT将为您提供每条array300相同的300条记录,id并为它们提供帮助bucket_num(1表示第1个元素,2表示下3个,依此类推).

然后使用此选择来获取avg存储桶中的元素:

SELECT id, avg(val) as avg_val
FROM (...previous select here...)
GROUP BY id, bucket_num
Run Code Online (Sandbox Code Playgroud)

下一步 - 只是汇总avg_val到数组:

SELECT id, array_agg(avg_val) as array100
FROM (...previous select here...)
GROUP BY id
Run Code Online (Sandbox Code Playgroud)

联系方式:UNNEST,NTILE,ARRAY_AGG,OVER(PARTITION BY)

UPD:试试这个功能:

CREATE OR REPLACE FUNCTION public.array300_to_100 (
  p_array300 numeric []
)
RETURNS numeric [] AS
$body$
DECLARE
  dim_start int = array_length(p_array300, 1); --size of input array
  dim_end int = 100; -- size of output array
  dim_step int = dim_start / dim_end; --avg batch size
  tmp_sum NUMERIC; --sum of the batch
  result_array NUMERIC[100]; -- resulting array
BEGIN

  FOR i IN 1..dim_end LOOP --from 1 to 100.
    tmp_sum = 0;

    FOR j IN (1+(i-1)*dim_step)..i*dim_step LOOP --from 1 to 3, 4 to 6, ...
      tmp_sum = tmp_sum + p_array300[j];  
    END LOOP; 

    result_array[i] = tmp_sum / dim_step;
  END LOOP; 

  RETURN result_array;
END;
$body$
LANGUAGE 'plpgsql'
IMMUTABLE
RETURNS NULL ON NULL INPUT;
Run Code Online (Sandbox Code Playgroud)

它需要一个array300输出一个array100.要使用它:

SELECT id, array300_to_100(array300)
FROM table1;
Run Code Online (Sandbox Code Playgroud)

如果你有任何理解它 - 请问我.

  • 很好的应用`ntile()`. (3认同)

A.H*_*.H. 6

将伊戈尔的碎片放入另一种形式:

 select id, array300, (
    select array_agg(z) from
    (
        select avg(x) from 
        (
            select x, ntile(array_length(array300,1)/3) over() from unnest(array300) x
        ) y 
        group by ntile
    ) z
) array100
from your_table
Run Code Online (Sandbox Code Playgroud)

对于像这样的小示例表

 id |       array300        
----+-----------------------
  1 | {110,25,53,110,25,53}
  2 | {56,75,59,110,25,53}
  3 | {65,93,82,110,25,53}
  4 | {75,70,80,110,25,53}
Run Code Online (Sandbox Code Playgroud)

结果是:

 id |       array300        |                   array100                    
----+-----------------------+-----------------------------------------------
  1 | {110,25,53,110,25,53} | {(62.6666666666666667),(62.6666666666666667)}
  2 | {56,75,59,110,25,53}  | {(63.3333333333333333),(62.6666666666666667)}
  3 | {65,93,82,110,25,53}  | {(80.0000000000000000),(62.6666666666666667)}
  4 | {75,70,80,110,25,53}  | {(75.0000000000000000),(62.6666666666666667)}
(4 rows)
Run Code Online (Sandbox Code Playgroud)

编辑我的第一个版本使用了修复程序ntile(2).这仅适用于大小为6的源数组.我已经通过使用array_length(array300,1)/3而修复了它.