一、目的
自定义一个分析函数,实现median(中位值)聚合函数的功能:对输入的一组数排序,当元素数量为奇数时,返回中间元素的值;当元素数量为偶数时,返回中间两个元数的平均值。
二、定义数值数组类型
create or replace type t_number_array is varray(100) of number
三、定义分析函数类型
1、头
create or replace type t_med as object ( numbers t_number_array, --初始化 static function odciaggregateinitialize(this in out t_med) return number, --遍历 member function odciaggregateiterate(self in out t_med, value number) return number, --结束 member function odciaggregateterminate(self in t_med, returnvalue out number, flags in number) return number, --合并 member function odciaggregatemerge(self in out t_med, ctx2 in t_med) return number )
2、体
CREATE OR REPLACE TYPE BODY t_med IS --初始化 STATIC FUNCTION odciaggregateinitialize(this IN OUT t_med) RETURN NUMBER IS BEGIN this := t_med(t_number_array()); RETURN odciconst.success; END; --遍历 MEMBER FUNCTION odciaggregateiterate(SELF IN OUT t_med, VALUE NUMBER) RETURN NUMBER IS --将元素按倒序,插入到数组中 --新元素将要插入的位置 i_loc1 INTEGER; --移位时的数组指针 i_loc2 INTEGER; BEGIN --空值不处理 IF VALUE IS NULL THEN RETURN odciconst.success; END IF; --假定初始的位置是最后 i_loc1 := self.numbers.count + 1; FOR i IN 1 .. self.numbers.count LOOP IF VALUE > self.numbers(i) THEN i_loc1 := i; GOTO outer1; END IF; END LOOP; <<outer1>> --数组扩充一个元素 self.numbers.extend; i_loc2 := self.numbers.count; --插入位置的元素后移 WHILE i_loc2 > i_loc1 LOOP self.numbers(i_loc2) := self.numbers(i_loc2 - 1); i_loc2 := i_loc2 - 1; END LOOP; --新元素填入 self.numbers(i_loc1) := VALUE; RETURN odciconst.success; END; --结束 MEMBER FUNCTION odciaggregateterminate(SELF IN t_med, returnvalue OUT NUMBER, flags IN NUMBER) RETURN NUMBER IS BEGIN IF self.numbers.count = 0 THEN returnvalue := NULL; ELSE IF self.numbers.count MOD 2 = 0 THEN --元素数量是偶数,返回中间两个元素的平均值 returnvalue := (self.numbers(self.numbers.count / 2 + 1) + self.numbers(self.numbers.count / 2)) / 2; ELSE --元素数量是奇数,返回中间元素 returnvalue := self.numbers((self.numbers.count - 1) / 2 + 1); END IF; END IF; RETURN odciconst.success; END; --合并 MEMBER FUNCTION odciaggregatemerge(SELF IN OUT t_med, ctx2 IN t_med) RETURN NUMBER IS BEGIN NULL; RETURN odciconst.success; END; END;
四、定义分析函数
create or replace function f_med(p_value number) return number aggregate using t_med;
五、测试
1、表
create table test1 (
user_name varchar2(30),
deposit_date date,
amount number);
2、数据
delete from test1;
insert into test1 values ('jack',trunc(sysdate),100);
insert into test1 values ('jack',trunc(sysdate),1000);
insert into test1 values ('jack',trunc(sysdate),10000);
insert into test1 values ('jack',trunc(sysdate),100000);
3、查询
SELECT user_name,
deposit_date,
amount,
median(amount) over(PARTITION BY user_name, deposit_date) med_amount,
AVG(amount) over(PARTITION BY user_name, deposit_date) avg_amount,
f_med(amount) over(PARTITION BY user_name, deposit_date) med_amount2
FROM test1;
USER_NAMEDEPOSIT_DATEAMOUNTMED_AMOUNTAVG_AMOUNTMED_AMOUNT2
1jack2010-12-161005500277755500
2jack2010-12-1610005500277755500
3jack2010-12-16100005500277755500
4jack2010-12-161000005500277755500