文章概要:
KES的SQL的语法暂时不兼容oracle的自定义聚合函数的创建语法和流程,但是可以使用KES已支持的语法改写。
本文整理和简单解析了自定义聚合函数的原理和解读了范例代码。
并根据客户代码进行了改写。
一,oracle自定义聚合函数的简析
oracle的自定义聚合函数需要实现4个ODCIAggregate 接口函数,被声明和定义在一个对象类型中。
这些函数定义了任何一个聚集函数内部需要实现的操作,
这些函数分别是 initialization, iteration, merging(定义了并行聚合enable parallel时会调用) 和 termination。如下图是自定义聚合函数的处理流程:
1,自定义聚合函数的并行流程:
|--------------|
| |
\|/ |
ODCIAggregateInitialize -------> ODCIAggregateIterate
|
|
| -----> ODCIAGGREGATEMERGE -----> ODCIAGGREGATETERMINATE
|
|--------------|
| |
\|/ |
ODCIAggregateInitialize -------> ODCIAggregateIterate
自定义聚合函数的串行流程(实测不会调用ODCIAGGREGATEMERGE):
|--------------|
| |
\|/ |
ODCIAggregateInitialize-------> ODCIAggregateIterate -----> ODCIAGGREGATETERMINATE
从上可以看出,并行是会调用ODCIAGGREGATEMERGE,但是非并行未调用ODCIAGGREGATEMERGE。
2,oracle自定义聚合函数的实例解析
举一个计算第二大值得案例为例
接口的定义:
create type SecondMaxImpl as object
(
--自定义保存最大值
max NUMBER,
--自定义保存第二大值
secmax NUMBER,
--初始化函数,必须要实现的方法,用于在聚合运算的最开始部分,初始化上下文环境
static function ODCIAggregateInitialize(sctx IN OUT SecondMaxImpl) return number,
--迭代运算函数,oracle依据该函数进行迭代运算,
--第一个参数self,为聚合运算的上下文,
--第二个参数value,为当前需要处理的值,可以为number varchar2等类型,
--在迭代过程中,如果当前值为null,则忽略该次迭代
member function ODCIAggregateIterate(self IN OUT SecondMaxImpl, value IN number) return number,
--(oracle会有选择执行该步骤)该函数用于合并两个上下文到一个上下文中,在并行和串行环境下均有可能发挥作用
member function ODCIAggregateMerge(self IN OUT SecondMaxImpl, ctx2 IN SecondMaxImpl) return number,
--该函数在聚合运算的最后一步运行,用于对结果进行处理并返回处理结果,
--第一个参数self为上下文,
--第二个参数returnValue为返回值,可以为number,varchar2等类型
--第三个参数flags为标识位
member function ODCIAggregateTerminate(self IN SecondMaxImpl, returnValue OUT number, flags IN number) return number
);
/
--聚合函数的定义和接口实现
create or replace type body SecondMaxImpl is
static function ODCIAggregateInitialize(sctx IN OUT SecondMaxImpl)
return number is
begin
sctx := SecondMaxImpl(0, 0); --初始化
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(
self IN OUT SecondMaxImpl,
value IN number
)
return number
is
begin
if value > self.max then
self.secmax := self.max;
self.max := value;
elsif value > self.secmax then
self.secmax := value;
end if;
return ODCIConst.Success;
end;
member function ODCIAggregateMerge(
self IN OUT SecondMaxImpl, --合并两个上下文(并行聚合有用。只能用于并行聚合?)
ctx2 IN SecondMaxImpl
)
return number
is
begin
if ctx2.max > self.max then
if ctx2.secmax > self.secmax then
self.secmax := ctx2.secmax;
else
self.secmax := self.max;
end if;
self.max := ctx2.max;
elsif ctx2.max > self.secmax then
self.secmax := ctx2.max;
end if;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(
self IN SecondMaxImpl,
returnValue OUT number,
flags IN number
)
return number is
begin
returnValue := self.secmax; --获取第二大值
--returnValue := self.max; --获取最大值
return ODCIConst.Success;
end;
end;
/
---创建聚合函数
CREATE FUNCTION SecondMax (input NUMBER) RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING SecondMaxImpl;
--构造测试数据,看看运行效果
create table tt02(
id int ,
name varchar(20),
sal number(6,2)
);
insert into tt02 values(12,'aaaa',1253.2);
insert into tt02 values(14,'aass',1965.3);
insert into tt02 values(13,'vvvv',2056.6);
insert into tt02 values(16,'aass',6562.1);
insert into tt02 values(15,'aass',4563.4);
insert into tt02 values(12,'aaaa',2532.2);
insert into tt02 values(14,'aass',1965.3);
insert into tt02 values(13,'vvvv',6556.6);
insert into tt02 values(16,'aass',8965.1);
insert into tt02 values(15,'aass',7854.4);
--测试验证(符合预期)
SQL> select id,SecondMax(sal) from tt02 group by id;
ID SECONDMAX(SAL)
---------- --------------
12 1253.2
13 2056.6
14 1965.3
16 6562.1
SQL> select /*+ parallel */ id,SecondMax(sal) from tt02 group by id;
ID SECONDMAX(SAL)
---------- --------------
12 1253.2
13 2056.6
14 1965.3
16 6562.1
--重新生成数据
delete from tt02;
declare
vv1 int;
vv2 int;
vv3 varchar2(20);
begin
for i in 1..10 loop
select abs(mod(dbms_random.random,10000)) into vv1 from dual;
select abs(mod(dbms_random.random,5)) into vv2 from dual;
select dbms_random.string('u',5) into vv3 from dual;
insert into tt02 values(vv2,vv3,vv1);
end loop;
end;
SQL> select * from tt02;
ID NAME SAL
---------- ---------------------------------------- ----------
3 IJTIJ 5978
4 JUAWT 2087
0 FPBMN 2218
0 AMBNZ 618
2 VFXJD 37
4 PEXGM 7983
2 CDQJT 877
2 ENQFX 3359
2 ICJFI 1220
0 XCGJX 1397
10 rows selected.
--二次验证(符合预期)
SQL> select id,SecondMax(sal) from tt02 group by id;
ID SECONDMAX(SAL)
---------- --------------
0 1397
2 1220
3 0
4 2087
SQL> select /*+ parallel */ id,SecondMax(sal) from tt02 group by id;
ID SECONDMAX(SAL)
---------- --------------
0 1397
2 1220
3 0
4 2087
实际上就改写而言,到此已经知道该函数的作用
二,KES语法改写oracle自定义聚合函数
1,oracle的自定义聚合函数定义及其分析验证
oracle自定义聚合函数sumc2如下,先对其进行一个简单的分析和功能验证:
--对象类型头(接口声明)
CREATE OR REPLACE EDITIONABLE TYPE "TYPESUMVARCHAR2" as object (
vsum VARCHAR2(4000),
--自定义聚集函数初始化设置,从这儿开始一个聚集函数
static function ODCIAggregateInitialize(sctx IN OUT TYPESUMVARCHAR2) return number,
--自定义聚集函数,最主要的步骤,这个函数定义我们的聚集函数具体做什么操作,后面的例子,是取最大值,最小值,平均值,还是做连接操作.self 为当前聚集函数的指针,用来与前面的计算结果进行关联
member function ODCIAggregateIterate(self IN OUT TYPESUMVARCHAR2,value IN varchar2) return number,
--终止聚集函数的处理,返回聚集函数处理的结果
member function ODCIAggregateTerminate(self IN TYPESUMVARCHAR2,returnValue OUT VARCHAR2, flags IN number) return number,
--用来合并两个聚集函数的两个不同的指针对应的结果,用户合并不同结果结的数据,特别是处理并行(parallel)查询聚集函数的时候.
member function ODCIAggregateMerge(self IN OUT TYPESUMVARCHAR2,ctx2 IN TYPESUMVARCHAR2) return number
);
对象类型体(接口定义)
CREATE OR REPLACE EDITIONABLE TYPE BODY "TYPESUMVARCHAR2" IS
--自定义聚集函数初始化设置,从这儿开始一个聚集函数
STATIC FUNCTION ODCIAGGREGATEINITIALIZE(
SCTX IN OUT TYPESUMVARCHAR2
)
RETURN NUMBER IS
BEGIN
SCTX := TYPESUMVARCHAR2('');
--初始化vsum
RETURN ODCICONST.SUCCESS;
END;
--自定义聚集函数,最主要的步骤,这个函数定义我们的聚集函数具体做什么操作,后面的例子,
--是取最大值,最小值,平均值,还是做连接操作.self 为当前聚集函数的指针,用来与前面的计算结果进行关联
MEMBER FUNCTION ODCIAGGREGATEITERATE(
SELF IN OUT TYPESUMVARCHAR2,
VALUE IN VARCHAR2
) RETURN NUMBER IS
BEGIN
--SELF.vsum := substr(SELF.vsum || ',' || VALUE,0,2000);
IF instr(
SELF.vsum,
value
) = 0
OR SELF.vsum IS NULL THEN
SELF.vsum := substr(
SELF.vsum || ',' || VALUE,
0,
2000
) ;
ELSE
SELF.vsum := substr(
SELF.vsum || '',
0,
2000
) ;
END IF ;
RETURN ODCICONST.SUCCESS;
END;
--终止聚集函数的处理,返回聚集函数处理的结果,(代码做了截取)
MEMBER FUNCTION ODCIAGGREGATETERMINATE(
SELF IN TYPESUMVARCHAR2,
RETURNVALUE OUT VARCHAR2,
FLAGS IN NUMBER
) RETURN NUMBER IS
BEGIN
RETURNVALUE := SUBSTR(
SELF.vsum,
2
);
RETURN ODCICONST.SUCCESS;
END;
--用来合并两个聚集函数的两个不同的指针对应的结果,用户合并不同结果结的数据,特别是处理并行(parallel)查询聚集函数的时候.
--此处默认未做任何动作(未执行合并)
MEMBER FUNCTION ODCIAGGREGATEMERGE(
SELF IN OUT TYPESUMVARCHAR2,
CTX2 IN TYPESUMVARCHAR2
)
RETURN NUMBER IS
BEGIN
RETURN ODCICONST.SUCCESS;
END;
END;
--创建自定义聚合函数
CREATE OR REPLACE FUNCTION sumc2(input varchar2)
RETURN varchar2
PARALLEL_ENABLE AGGREGATE
USING TYPESUMVARCHAR2;
根据上面的tt02表实测
SQL> select * from tt02;
ID NAME SAL
---------- ---------------------------------------- ----------
3 IJTIJ 5978
4 JUAWT 2087
0 FPBMN 2218
0 AMBNZ 618
2 VFXJD 37
4 PEXGM 7983
2 CDQJT 877
2 ENQFX 3359
2 ICJFI 1220
0 XCGJX 1397
SQL> select id,sumc2(name) from tt02 group by id;
ID SUMC2(NAME)
--------------------------------------------------------------------------------
0 FPBMN,XCGJX,AMBNZ
2 VFXJD,ICJFI,ENQFX,CDQJT
3 IJTIJ
4 JUAWT,PEXGM
更换表实测:
--teachers表如下:
teacher_id | teacher_name | age | sal | gender | title | position | department
------------+--------------+-----+----------+--------+----------+------------+------------
10001001 | 陈思宇 | 46 | 15689.00 | 男 | 特级教师 | 校长 | 校长室
10001002 | 文强 | 44 | 29942.00 | 男 | 特级教师 | 副校长 | 校长室
10001003 | 吴玲 | 41 | 29142.00 | 女 | 高级教师 | 办公室主任 | 办公室
10001004 | 章丽 | 41 | 28242.00 | 女 | 高级教师 | 教务处主任 | 教务处
10001005 | 张志东 | 41 | 28242.00 | 男 | 高级教师 | 财务处主任 | 财务处
10001006 | 熊浩宇 | 49 | 28356.00 | 女 | 一级教师 | 招生办主任 | 招生办
10001007 | 朱雯 | 49 | 24016.00 | 女 | 一级教师 | 招生办助理 | 招生办
10001008 | 张志强 | 49 | 23964.00 | 女 | 一级教师 | 财务处助理 | 财务处
10001009 | 朱国斌 | 49 | 21974.00 | 男 | 二级教师 | 财务处助理 | 财务处
oracle测试结果
select age,sumc2(title) from teachers group by age;
41 高级教师
44 特级教师
46 特级教师
49 一级教师,二级教师
通过代码和实际效果的实测,聚合函数sumc2作用是去重,获取去重后的拼接结果。
了解了客户原生代码和oracle自定义聚合功能后,
2,KES所支持的聚合函数基本原理
KES能支持的聚合函数(PLPGSQL)语法如下:
CREATE AGGREGATE name ( [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
SFUNC = sfunc, ---迭代函数,每行数据迭代调用计算结果
STYPE = state_data_type ----聚合函数返回的数据类型
[ , SSPACE = state_data_size ]
[ , FINALFUNC = ffunc ] ----每组的最终计算函数,可选
[ , FINALFUNC_EXTRA ]
[ , COMBINEFUNC = combinefunc ] ---聚合COMBINEFUNC函数,开启后在开启PARALLEL能并行
[ , SERIALFUNC = serialfunc ]
[ , DESERIALFUNC = deserialfunc ]
[ , INITCOND = initial_condition ] ---INITCOND是第一次调用SFUNC给第一个参数的传值,可以不写。
[ , MSFUNC = msfunc ]
[ , MINVFUNC = minvfunc ]
[ , MSTYPE = mstate_data_type ]
[ , MSSPACE = mstate_data_size ]
[ , MFINALFUNC = mffunc ]
[ , MFINALFUNC_EXTRA ]
[ , MINITCOND = minitial_condition ]
[ , SORTOP = sort_operator ]
[ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ] ----SAFE并行聚合
)
其中重点需要讲的是:
聚合函数是每组独立计算的,比如按上述teachers表的age聚合(GROUP BY age),那么就会分4组,4组分别内部进行计算。
--teachers表如下:
teacher_id | teacher_name | age | sal | gender | title | position | department
------------+--------------+-----+----------+--------+----------+------------+------------
10001001 | 陈思宇 | 46 | 15689.00 | 男 | 特级教师 | 校长 | 校长室
10001002 | 文强 | 44 | 29942.00 | 男 | 特级教师 | 副校长 | 校长室
10001003 | 吴玲 | 41 | 29142.00 | 女 | 高级教师 | 办公室主任 | 办公室
10001004 | 章丽 | 41 | 28242.00 | 女 | 高级教师 | 教务处主任 | 教务处
10001005 | 张志东 | 41 | 28242.00 | 男 | 高级教师 | 财务处主任 | 财务处
10001006 | 熊浩宇 | 49 | 28356.00 | 女 | 一级教师 | 招生办主任 | 招生办
10001007 | 朱雯 | 49 | 24016.00 | 女 | 一级教师 | 招生办助理 | 招生办
10001008 | 张志强 | 49 | 23964.00 | 女 | 一级教师 | 财务处助理 | 财务处
10001009 | 朱国斌 | 49 | 21974.00 | 男 | 二级教师 | 财务处助理 | 财务处
1),SFUNC迭代函数,假设自定义如下:
CREATE OR REPLACE FUNCTION YOUR_SFUNC_NAME (numeric, numeric, numeric......)
RETURNS numeric
as
begin
.......(省略)
end
这个函数就是每行数据的迭代函数
参数一:$1, 上一次迭代的计算结果;
参数二:$2, YOUR_AGGREGATE_NAME的第一个参数(如果聚合函数传入的是表的列,则表示当前行数据)
参数三:$3, YOUR_AGGREGATE_NAME的第二个参数(如果是个固定值,比如数值2,则每次传入2)
参数四:$4, YOUR_AGGREGATE_NAME的第三个参数
...........
2),FINALFUNC最终函数,假设自定义如下:
CREATE OR REPLACE FUNCTION YOUR_FINALFUNC_NAME (numeric) ---只有一个参数,SFUNC函数返回的是numeric,所以这里是numeric
RETURNS numeric ---聚合返回类型,所以这里是numeric
as
begin
.......(省略)
end
通过YOUR_SFUNC_NAME函数将每组计算完后,,最后调用一次,也就是说最后还可以进行一次规则计算。
3),YOUR_AGGREGATE_NAME聚合函数
聚合函数的定义会引用到上述YOUR_SFUNC_NAME和YOUR_FINALFUNC_NAME函数,最终达成特定目标的计算。
一个典型的非并行使用举例;
CREATE AGGREGATE YOUR_AGGREGATE_NAME(numeric, numeric) ---接受两个参数,会作为SFUNC函数的后两个参数
(
INITCOND = xxxx, ---INITCOND是第一次调用YOUR_SFUNC_NAME函数,给第一个参数的传值xxxx,可以不写。
STYPE = numeric, ---聚合函数返回的数据类型numeric
SFUNC = YOUR_SFUNC_NAME, ---每组的自定义迭代函数
FINALFUNC = YOUR_FINALFUNC_NAME ---每组的小结函数
);
掌握了以上基本语法信息后已经可以编写自定义聚合函数了。
参考于这篇文章:
Postgresql自定义聚合函数入门案例_pgsql自定义聚合函数_高铭杰的博客-CSDN博客
DROP AGGREGATE myavg(integer);
CREATE TABLE t_taxi(trip_id int, km numeric);
insert into t_taxi values (1, 3.4);
insert into t_taxi values (1, 5.3);
insert into t_taxi values (1, 2.9);
insert into t_taxi values (2, 9.3);
insert into t_taxi values (2, 1.6);
insert into t_taxi values (2, 4.3);
trip_id | km
---------+-----
1 | 3.4
1 | 5.3
1 | 2.9
2 | 9.3
2 | 1.6
2 | 4.3
————————————————
CREATE OR REPLACE FUNCTION taxi_accum (numeric, numeric, numeric)
RETURNS numeric AS
$$
BEGIN
RAISE NOTICE 'prev:[%] curr:(%) outer:(%) return:(%)', $1, $2, $3, $1 + $2 * $3;
RETURN $1 + $2 * $3;
END;
$$
LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION taxi_final (numeric)
RETURNS numeric AS
$$
BEGIN
RAISE NOTICE 'final:(%) return:(%)', $1, round($1 + 5, -1);
RETURN round($1 + 5, -1);
END;
$$
LANGUAGE 'plpgsql';
CREATE AGGREGATE taxi(numeric, numeric)
(
SFUNC = taxi_accum,
STYPE = numeric,
FINALFUNC = taxi_final,
INITCOND = 3.50
);
--测试
test=# SELECT trip_id, taxi(km, 2.20), 3.50 + sum(km)*2.2 AS manual FROM t_taxi GROUP BY trip_id;
test-# /
NOTICE: prev:[3.50] curr:(3.4) outer:(2.20) return:(10.980)
NOTICE: prev:[10.980] curr:(5.3) outer:(2.20) return:(22.640)
NOTICE: prev:[22.640] curr:(2.9) outer:(2.20) return:(29.020)--对trip_id为1的组进行SFUNC函数迭代计算
NOTICE: prev:[3.50] curr:(9.3) outer:(2.20) return:(23.960)
NOTICE: prev:[23.960] curr:(1.6) outer:(2.20) return:(27.480)
NOTICE: prev:[27.480] curr:(4.3) outer:(2.20) return:(36.940)--对trip_id为2的组进行SFUNC函数迭代计算
NOTICE: final:(29.020) return:(30)--对trip_id为1的组将SFUNC函数返回的结果(参数第一个值)进行最终计算
NOTICE: final:(36.940) return:(40)--对trip_id为2的组将SFUNC函数返回的结果(参数第一个值)进行最终计算
trip_id | taxi | manual
---------+------+--------
1 | 30 | 29.02
2 | 40 | 36.94
(2 rows)
Time: 1.775 ms
--可以看到基本的聚合函数(非并行)流程就是
--1,使用SFUNC函数对每组数据进行迭代计算
--2,每组数据计算完成后,使用FINALFUNC将每组的SFUNC结果
3,KES自定义聚合函数改写
使用plpgsql语法改写(对应上述oracle的sumc2函数)后:
--定义每行数据的迭代函数
CREATE OR REPLACE FUNCTION agg(v1 varchar,v2 varchar)
RETURNS varchar IMMUTABLE
AS
$$
BEGIN
if v1 is null or LENGTH(v1) = 0 then
v1 := substr(v2, 0 , 2000) ;
ELSIF v2 is null and v1 is not null then
v1 := substr(v1, 0 , 2000) ;
ELSIF instr( v1, v2 ) = 0 then ---如果是不包含关系(则拼接)
v1 := substr(v1 || ',' || v2 , 0 , 2000) ;
else
v1 := substr(v1 , 0 , 2000) ;
end if ;
return v1;
end;
$$LANGUAGE 'plpgsql';
--定义每组的最终函数
CREATE OR REPLACE FUNCTION agg_final (varchar)
RETURNS varchar AS
$$
BEGIN
RETURN $1; ---本例子无需任何额外处理
END;
$$
LANGUAGE 'plpgsql';
---定义聚合函数
CREATE OR REPLACE AGGREGATE sumc2 (varchar)
(
SFUNC = agg, ---每组的自定义迭代函数
STYPE = varchar, ---聚合函数返回的数据类型
FINALFUNC = agg_final, ---每组的最终函数
INITCOND ='' --INITCOND是第一次调用agg函数,给第一个参数的传值。
);
对上述改写后的聚合函数进行基本功能的验证
kes测试:
--建表
CREATE table teachers (
teacher_id number(8) not null,
teacher_name varchar2 (40) not null,
age number(2),
sal number(8,2) default 0,
gender varchar2(10),
title varchar2(20),
POSITION varchar2(20),
department varchar2 (40) not null,
constraint teach_ch_gender check ( gender in ('男','女')),
constraint teach_ch_title check ( title in ('三级教师','二级教师','一级教师','高级教师','特级教师')),
primary key(teacher_id,teacher_name)
);
--建数据
insert into teachers values(10001001,'陈思宇',46,15689.00,'男','特级教师','校长','校长室');
insert into teachers values(10001002,'文强',44,14971.00,'男','特级教师','副校长','校长室');
insert into teachers values(10001003,'吴玲',41,14571.00,'女','高级教师','办公室主任','办公室');
insert into teachers values(10001004,'章丽',41,14121.00,'女','高级教师','教务处主任','教务处');
insert into teachers values(10001005,'张志东',41,14121.00,'男','高级教师','财务处主任','财务处');
insert into teachers values(10001006,'熊浩宇',49,14178.00,'女','一级教师','招生办主任','招生办');
insert into teachers values(10001007,'朱雯',49,12008.00,'女','一级教师','招生办助理','招生办');
insert into teachers values(10001008,'张志强',49,11982.00,'女','一级教师','财务处助理','财务处');
insert into teachers values(10001009,'朱国斌',49,10987.00,'男','二级教师','财务处助理','财务处');
--查看表
test=# select * from teachers;
test-# /
teacher_id | teacher_name | age | sal | gender | title | position | department
------------+--------------+-----+----------+--------+----------+------------+------------
10001001 | 陈思宇 | 46 | 15689.00 | 男 | 特级教师 | 校长 | 校长室
10001002 | 文强 | 44 | 29942.00 | 男 | 特级教师 | 副校长 | 校长室
10001003 | 吴玲 | 41 | 29142.00 | 女 | 高级教师 | 办公室主任 | 办公室
10001004 | 章丽 | 41 | 28242.00 | 女 | 高级教师 | 教务处主任 | 教务处
10001005 | 张志东 | 41 | 28242.00 | 男 | 高级教师 | 财务处主任 | 财务处
10001006 | 熊浩宇 | 49 | 28356.00 | 女 | 一级教师 | 招生办主任 | 招生办
10001007 | 朱雯 | 49 | 24016.00 | 女 | 一级教师 | 招生办助理 | 招生办
10001008 | 张志强 | 49 | 23964.00 | 女 | 一级教师 | 财务处助理 | 财务处
10001009 | 朱国斌 | 49 | 21974.00 | 男 | 二级教师 | 财务处助理 | 财务处
(9 rows)
--测试
test=# select age,sumc2(title) from teachers group by age;
test-# /
age | sumc2
-----+-------------------
49 | 一级教师,二级教师
44 | 特级教师
46 | 特级教师
41 | 高级教师
(4 rows)
Time: 1.517 ms
创建一个新的测试表,再次测试
drop table tt02;
create table tt02 (
id int,
name varchar2(200)
);
--kes:
declare
v int;
begin
for i in 1..100000 loop
select ceil(random()*10000 + 1) into v from dual;
insert into tt02 values(v,'特级教师');
select ceil(random()*10000 + 1) into v from dual;
insert into tt02 values(v,'高级教师');
end loop;
end;
--oracle:
declare
v int;
begin
for i in 1..1000 loop
select dbms_random.value(0,100000) into v from dual;
insert into tt02 values(v,'特级教师');
select dbms_random.value(0,100000) into v from dual;
insert into tt02 values(v,'高级教师');
end loop;
end;
test=# select * from tt02;
id | name
----+----------
1 | 特级教师
2 |
3 | 特级教师
4 | 中级教师
5 | 特级教师
6 |
7 | 特级教师
8 | 中级教师
(8 rows)
test=# select sumc2(name) from tt02;
test-# /
sumc2
-------------------
特级教师,中级教师
(1 row)
故此测试结果和oracle一致,符合基本的预期
注意:以上代码内容未对并行条件下进行考虑,后期将对齐进行讲解
标签:聚合,函数,自定义,--,into,Kingbase,values,ES From: https://www.cnblogs.com/kingbase/p/17561077.html