2012-12-10 38 views
13

Tôi có một bảng như thế này:chức năng tổng hợp trên mảng

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

array300 cột là một mảng của 300 yếu tố. Tôi cần có các mảng gồm 100 phần tử với mỗi phần tử biểu thị mức trung bình của 3 phần tử là array300. Ví dụ này là câu trả lời sẽ như thế nào:
array100
{62,66, ...}
{63,33, ...}
{80, ...}
{78.33, ...}

+0

Xem m y cập nhật câu trả lời. –

Trả lời

11

Hãy thử một cái gì đó như thế này:

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

SELECT này sẽ cung cấp cho bạn 300 hồ sơ cho mỗi array300 với cùng id và assing họ bucket_num (1 cho linh sam 3 yếu tố, 2 cho tới 3, và vân vân).

Sau đó sử dụng chọn này để có được những avg của các yếu tố trong xô:

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

Tiếp - chỉ cần tổng hợp avg_val vào mảng:

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

chi tiết: unnest, ntile, array_agg, OVER (PARTITION BY)

UPD: Thử chức năng này:

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; 

Phải mất một array300 và đầu ra một array100. Để sử dụng:

SELECT id, array300_to_100(array300) 
FROM table1; 

Nếu bạn gặp bất kỳ vấn đề gì khi hiểu - chỉ cần hỏi tôi.

+3

Ứng dụng đẹp của 'ntile()'. –

6

Đưa các mảnh của Igor sang loại hình khác:

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 

Đối với một bảng ví dụ nhỏ như

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} 

kết quả này là:

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) 

Sửa My đầu tiên phiên bản đã sử dụng bản sửa lỗi ntile(2). Điều này chỉ làm việc cho mảng nguồn kích thước 6. Tôi đã cố định bằng cách sử dụng array_length(array300,1)/3 thay thế.

1

Tôi không thể trả lời câu hỏi của bạn hoàn toàn, tuy nhiên tôi đã tìm thấy hàm tổng hợp để tổng hợp các mảng số nguyên. Có lẽ ai đó (hoặc bạn) có thể sửa đổi nó thành avg.

Nguồn: 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) 
-1

Bạn luôn có thể cố gắng cho dù biến thể hardcoded hoạt động tốt hơn:

select 

array[ 
(input_array[1] + input_array[101] + input_array[201])/3::numeric, 
(input_array[2] + input_array[102] + input_array[202])/3::numeric, 
(input_array[3] + input_array[103] + input_array[203])/3::numeric, 
(input_array[4] + input_array[104] + input_array[204])/3::numeric, 
(input_array[5] + input_array[105] + input_array[205])/3::numeric, 
(input_array[6] + input_array[106] + input_array[206])/3::numeric, 
(input_array[7] + input_array[107] + input_array[207])/3::numeric, 
(input_array[8] + input_array[108] + input_array[208])/3::numeric, 
(input_array[9] + input_array[109] + input_array[209])/3::numeric, 
(input_array[10] + input_array[110] + input_array[210])/3::numeric, 
(input_array[11] + input_array[111] + input_array[211])/3::numeric, 
(input_array[12] + input_array[112] + input_array[212])/3::numeric, 
(input_array[13] + input_array[113] + input_array[213])/3::numeric, 
(input_array[14] + input_array[114] + input_array[214])/3::numeric, 
(input_array[15] + input_array[115] + input_array[215])/3::numeric, 
(input_array[16] + input_array[116] + input_array[216])/3::numeric, 
(input_array[17] + input_array[117] + input_array[217])/3::numeric, 
(input_array[18] + input_array[118] + input_array[218])/3::numeric, 
(input_array[19] + input_array[119] + input_array[219])/3::numeric, 
(input_array[20] + input_array[120] + input_array[220])/3::numeric, 
(input_array[21] + input_array[121] + input_array[221])/3::numeric, 
(input_array[22] + input_array[122] + input_array[222])/3::numeric, 
(input_array[23] + input_array[123] + input_array[223])/3::numeric, 
(input_array[24] + input_array[124] + input_array[224])/3::numeric, 
(input_array[25] + input_array[125] + input_array[225])/3::numeric, 
(input_array[26] + input_array[126] + input_array[226])/3::numeric, 
(input_array[27] + input_array[127] + input_array[227])/3::numeric, 
(input_array[28] + input_array[128] + input_array[228])/3::numeric, 
(input_array[29] + input_array[129] + input_array[229])/3::numeric, 
(input_array[30] + input_array[130] + input_array[230])/3::numeric, 
(input_array[31] + input_array[131] + input_array[231])/3::numeric, 
(input_array[32] + input_array[132] + input_array[232])/3::numeric, 
(input_array[33] + input_array[133] + input_array[233])/3::numeric, 
(input_array[34] + input_array[134] + input_array[234])/3::numeric, 
(input_array[35] + input_array[135] + input_array[235])/3::numeric, 
(input_array[36] + input_array[136] + input_array[236])/3::numeric, 
(input_array[37] + input_array[137] + input_array[237])/3::numeric, 
(input_array[38] + input_array[138] + input_array[238])/3::numeric, 
(input_array[39] + input_array[139] + input_array[239])/3::numeric, 
(input_array[40] + input_array[140] + input_array[240])/3::numeric, 
(input_array[41] + input_array[141] + input_array[241])/3::numeric, 
(input_array[42] + input_array[142] + input_array[242])/3::numeric, 
(input_array[43] + input_array[143] + input_array[243])/3::numeric, 
(input_array[44] + input_array[144] + input_array[244])/3::numeric, 
(input_array[45] + input_array[145] + input_array[245])/3::numeric, 
(input_array[46] + input_array[146] + input_array[246])/3::numeric, 
(input_array[47] + input_array[147] + input_array[247])/3::numeric, 
(input_array[48] + input_array[148] + input_array[248])/3::numeric, 
(input_array[49] + input_array[149] + input_array[249])/3::numeric, 
(input_array[50] + input_array[150] + input_array[250])/3::numeric, 
(input_array[51] + input_array[151] + input_array[251])/3::numeric, 
(input_array[52] + input_array[152] + input_array[252])/3::numeric, 
(input_array[53] + input_array[153] + input_array[253])/3::numeric, 
(input_array[54] + input_array[154] + input_array[254])/3::numeric, 
(input_array[55] + input_array[155] + input_array[255])/3::numeric, 
(input_array[56] + input_array[156] + input_array[256])/3::numeric, 
(input_array[57] + input_array[157] + input_array[257])/3::numeric, 
(input_array[58] + input_array[158] + input_array[258])/3::numeric, 
(input_array[59] + input_array[159] + input_array[259])/3::numeric, 
(input_array[60] + input_array[160] + input_array[260])/3::numeric, 
(input_array[61] + input_array[161] + input_array[261])/3::numeric, 
(input_array[62] + input_array[162] + input_array[262])/3::numeric, 
(input_array[63] + input_array[163] + input_array[263])/3::numeric, 
(input_array[64] + input_array[164] + input_array[264])/3::numeric, 
(input_array[65] + input_array[165] + input_array[265])/3::numeric, 
(input_array[66] + input_array[166] + input_array[266])/3::numeric, 
(input_array[67] + input_array[167] + input_array[267])/3::numeric, 
(input_array[68] + input_array[168] + input_array[268])/3::numeric, 
(input_array[69] + input_array[169] + input_array[269])/3::numeric, 
(input_array[70] + input_array[170] + input_array[270])/3::numeric, 
(input_array[71] + input_array[171] + input_array[271])/3::numeric, 
(input_array[72] + input_array[172] + input_array[272])/3::numeric, 
(input_array[73] + input_array[173] + input_array[273])/3::numeric, 
(input_array[74] + input_array[174] + input_array[274])/3::numeric, 
(input_array[75] + input_array[175] + input_array[275])/3::numeric, 
(input_array[76] + input_array[176] + input_array[276])/3::numeric, 
(input_array[77] + input_array[177] + input_array[277])/3::numeric, 
(input_array[78] + input_array[178] + input_array[278])/3::numeric, 
(input_array[79] + input_array[179] + input_array[279])/3::numeric, 
(input_array[80] + input_array[180] + input_array[280])/3::numeric, 
(input_array[81] + input_array[181] + input_array[281])/3::numeric, 
(input_array[82] + input_array[182] + input_array[282])/3::numeric, 
(input_array[83] + input_array[183] + input_array[283])/3::numeric, 
(input_array[84] + input_array[184] + input_array[284])/3::numeric, 
(input_array[85] + input_array[185] + input_array[285])/3::numeric, 
(input_array[86] + input_array[186] + input_array[286])/3::numeric, 
(input_array[87] + input_array[187] + input_array[287])/3::numeric, 
(input_array[88] + input_array[188] + input_array[288])/3::numeric, 
(input_array[89] + input_array[189] + input_array[289])/3::numeric, 
(input_array[90] + input_array[190] + input_array[290])/3::numeric, 
(input_array[91] + input_array[191] + input_array[291])/3::numeric, 
(input_array[92] + input_array[192] + input_array[292])/3::numeric, 
(input_array[93] + input_array[193] + input_array[293])/3::numeric, 
(input_array[94] + input_array[194] + input_array[294])/3::numeric, 
(input_array[95] + input_array[195] + input_array[295])/3::numeric, 
(input_array[96] + input_array[196] + input_array[296])/3::numeric, 
(input_array[97] + input_array[197] + input_array[297])/3::numeric, 
(input_array[98] + input_array[198] + input_array[298])/3::numeric, 
(input_array[99] + input_array[199] + input_array[299])/3::numeric, 
(input_array[100] + input_array[200] + input_array[300])/3::numeric 
] 

from tmp.test 
1

Đây có phải là bất kỳ nhanh hơn?

Chỉnh sửa: Đây là tao nhã hơn:

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 

Kết thúc chỉnh sửa

Edit2 Đây là ngắn nhất chọn tôi có thể nghĩ:

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 

Cuối edit2

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 
Các vấn đề liên quan