14

私はこのようなテーブルを持っています:

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

array300列は、300個の要素の配列です。すべての要素がarray300の3つの要素の平均を表す100要素の配列が必要です。この例では、答えは次のようになります
。array100
{62.66、...}
{63.33、...}
{80、...}
{78.33、...}

4

4 に答える 4

11

次のようなものを試してください。

SELECT id, unnest(array300) as val, ntile(100) OVER (PARTITION BY id) as bucket_num
FROM your_table

これにより、同じものごとにSELECT300レコードが得られ、それらを評価します(最初の3つの要素に1つ、次の3つの要素に2つなど)。array300idbucket_num

次に、この選択を使用avgして、バケット内の要素を取得します。

SELECT id, avg(val) as avg_val
FROM (...previous select here...)
GROUP BY id, bucket_num

avg_val次へ-を配列に集約するだけです:

SELECT id, array_agg(avg_val) as array100
FROM (...previous select here...)
GROUP BY id

詳細:unnestntilearray_aggOVER(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;

1つを取り、1つarray300を出力しますarray100。それを使用するには:

SELECT id, array300_to_100(array300)
FROM table1;

それを理解するのに問題がある場合は、私に聞いてください。

于 2012-12-10T16:05:46.487 に答える
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

このような小さな例のテーブルの場合

 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}

結果は次のとおりです。

 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)

編集私の最初のバージョンは修正を使用しましたntile(2)。これは、サイズ6のソース配列でのみ機能しましたarray_length(array300,1)/3。代わりにを使用して修正しました。

于 2012-12-12T19:01:38.123 に答える
1

あなたの質問に完全に答えることはできませんが、整数配列を合計するための集計関数を見つけました。おそらく誰か(またはあなた)がそれを平均に変更することができます。

ソース:http ://archives.postgresql.org/pgsql-sql/2005-04/msg00402.php

CREATE OR REPLACE FUNCTION array_add(int[],int[]) RETURNS int[] AS '
  DECLARE
    x ALIAS FOR $1;
    y ALIAS FOR $2;
    a int;
    b int;
    i int;
    res int[];
  BEGIN
    res = x;

    a := array_lower (y, 1);
    b := array_upper (y, 1);

    IF a IS NOT NULL THEN
      FOR i IN a .. b LOOP
        res[i] := coalesce(res[i],0) + y[i];
      END LOOP;
    END IF;

    RETURN res;
  END;
'
LANGUAGE plpgsql STRICT IMMUTABLE;

--- then this aggregate lets me sum integer arrays...

CREATE AGGREGATE sum_integer_array (
    sfunc = array_add,
    basetype = INTEGER[],
    stype = INTEGER[],
    initcond = '{}'
);


Here's how my sample table looked  and my new array summing aggregate
and function:

#SELECT * FROM arraytest ;
 id | somearr
----+---------
 a  | {1,2,3}
 b  | {0,1,2}
(2 rows)

#SELECT sum_integer_array(somearr) FROM arraytest ;
 sum_integer_array
-------------------
 {1,3,5}
(1 row)
于 2012-12-18T13:47:38.463 に答える
1

これはもっと速いですか?

編集:これはよりエレガントです:

with  t as (select generate_series(1, 100,1) a , generate_series(101,200,1) b , generate_series(201,300,1) c)

    select 
        id,
        array_agg((array300[a] + array300[b] + array300[c]) / 3::numeric order by a)  as avg
    from 
        t,
        tmp.test2
    group by 
        id

編集終了

Edit2これは私が考えることができる最短の選択です:

select 
    id,
    array_agg((array300[a] + array300[a+100] + array300[a+200]) / 3::numeric order by a)  as avg
from 
    (select generate_series(1, 100,1) a) t,
    tmp.test2
group by 
    id

編集の終わり2

with 

t as (select generate_series(1, 100,1) a , generate_series(101,200,1) b , generate_series(201,300,1) c)

,u as (
    select 
        id,
        a,
        (array300[a] + array300[b] + array300[c]) / 3::numeric as avg
    from 
        t,
        tmp.test2 /* table with arrays - id, array300 */
    order by 
        id,
        a
 )

select 
    id, 
    array_agg(avg)
from 
    u 
group by 
    id
于 2012-12-18T15:00:02.253 に答える