This solutions uses an algorithm so a double loop isn't needed:
http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance CREATE OR REPLACE type rec_parms as object (average number, weight number)
/
create or replace type agg_t as object (
sum_avg_x_gew number,
sum_avg2_x_gew number,
sum_weight number,
static function ODCIAggregateInitialize(sctx in out agg_t)
return number,
member function ODCIAggregateIterate (self in out agg_t,
value in rec_parms )
return number,
member function ODCIAggregateTerminate (self in agg_t ,
return_value out number,
flags in number )
return number,
member function ODCIAggregateMerge(self in out agg_t,
ctx2 in agg_t )
return number
);
/
create or replace type body agg_t is
static function ODCIAggregateInitialize(sctx in out agg_t)
return number is
begin
sctx := agg_t(0,0,0);
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(
self in out agg_t, value in rec_parms)
return number is
begin
sum_avg_x_gew := sum_avg_x_gew + value.average * value.weight;
sum_avg2_x_gew := sum_avg2_x_gew + value.average * value.average * value.weight;
sum_weight := sum_weight + value.weight;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(self in agg_t,
return_value out number, flags in number) return number is
l_mean number := 0;
l_variance number := 0;
begin
l_mean := sum_avg_x_gew / sum_weight;
l_variance := (sum_avg2_x_gew - (sum_avg_x_gew * l_mean))/sum_weight;
return_value := power(l_variance,0.5);
return ODCIConst.Success;
end;
member function ODCIAggregateMerge(self in out agg_t,
ctx2 in agg_t) return number is
begin
sum_avg_x_gew := ctx2.sum_avg_x_gew;
sum_avg2_x_gew := ctx2.sum_avg2_x_gew;
sum_weight := ctx2.sum_weight;
return ODCIConst.Success;
end;
end;
/
create or replace function stddev_w (input rec_parms) return number
parallel_enable aggregate using agg_t;
/
create table agg_test (
col1 number,
average number,
weight number
);
insert into agg_test values (1,10,10);
insert into agg_test values (1,100,1);
column weigthedstddev format 999999999999.99999
select
col1, stddev_w(rec_parms(average,weight)) weightedstddev from agg_test
group by
col1;
To clear everything:
drop table agg_test;
drop function stddev_w;
drop type agg_t;
drop type rec_parms;