升级到oracle 19.8后vm_concat函数不可用怎么解决

来源:这里教程网 时间:2026-03-03 19:38:26 作者:

最近,有客户反馈,vm_concat 函数在19.8 中怎么不存在了,在19.7 中还存在呢

借此机会对vm_concat 函数做一个全面的了解,

首先我们先介绍一下vm_concat 函数

 

1.vm_concat 函数的介绍

vm_concat 函数属于VMSYS 用户,其可以实现将多列记录聚合为一列记录,实现数据的压缩。

 

我们在Oracle11.2.0.4 用实验来展示下该函数的效果

首先我们创建一个测试表,并插入三行数据。

create table test (id number , name varchar2(20));

insert into test values(1,'a');

insert into test values(1,'b');

insert into test values(2,'c');

commit;

 

使用PLSQL 查询看下数据信息:

select * from test;

 

使用wm_concat 将多列记录聚合为一列,按id 分组。

select id,vmsys.wm_concat(name) as name from test group by id;

 PLSQL 中执行.

 

可以看出显示数据类型为CLOB 类型

所以如果返回的数据类型为CLOB, 我们需要使用to_char 进行类型转换

 

select id,to_char(vmsys.wm_concat(name)) as name from test group by id;

注意并不是所有版本的vm_concat 函数返回的数据类型都为CLOB

 

 

 

 

 

 

 

 

2. 不同数据库版本中 wm_concat 的差异:

vm_concat 属于Oracle 内部函数,Oracle 官方不会发布内部函数的变更信息,所以需要我们自己在各版本中进行测试。

 

10g 以及11g   10g 以及11g 中该函数可以正常使用

但是在10g 11g 中需要注意的是,vm_concat 返回的数据类型是不同的:

 

10.2.0.4/11.1.0.7/11.2.0.1 vm_concat 返回的是数据类型为 varchar2 类型 :

SQL> desc wmsys.wm_concat;

FUNCTION wmsys.wm_concat RETURNS VARCHAR2 

Argument Name      Type           In/Out  Default?

----------------------- ------------------------ -------- ---------

P1           VARCHAR2         IN

 

10.2.0.5/11.2.0.2 中, vm_concat 返回的数据类型为 clob 类型 :

SQL> desc wmsys.wm_concat;

FUNCTION wmsys.wm_concat RETURNS CLOB

Argument Name      Type           In/Out  Default?

----------------------- ------------------------ -------- ---------

P1           VARCHAR2         IN

 

12c

经过测试, 12.1/12.2 中,vm_concat 函数Oracle 已经不再支持使用,Oracle 推荐使用分析函数LISTAGG 代替vm_concat 函数的使用。

 

19c

经过测试, 19.3/19.7/19.8 中,vm_concat 函数Oracle 依旧不再支持使用。

 

3.wm_concat 的继任者 LISTAGG

 

分析函数LISTAGG 介绍:

作为单一集合,LISTAGG 它对所有行进行操作并返回单个输出行。

作为分组集合,此函数将对GROUP BY 子句定义的每个组进行操作并返回输出行。

 

分析函数LISTAGG 使用方法:

listagg(measure_expr delimiter) within group ( order by order_by_clause); 

解释:

measure_expr  可以是基于任何列的表达式

delimiter  分隔符,默认为NULL 

order_by_clause  决定了列值的拼接顺序

 

例子:

select listagg(name,',')within group(order by id) from test;

select id,listagg(name,',')within group(order by id) from test group by id;

 

4.oracle 关于 wm_concat 的建议

由于vm_concat 属于一个内部函数,并且Oracle 官方不会发布内部函数的变更信息, 所以Oracle 建议不要在应用程序中使用该函数,前面我们已经说了vm_concat 函数的前世今生,我们可以想象一下,如果我们的系统使用了大量的vm_concat 函数,当某一天数据库升级时,会出现很大的问题。所以Oracle 建议使用分析函数LISTAGG 来代替vm_concat 函数的使用,或者自己编写一个函数实现vm_concat 的功能,分析函数LISTAGG 的用法前面已经分析过了,那么如何自己编写一个函数来实现vm_concat

 

5. 手动编写函数实现 vm_concat

(1) 自定义函数类型

CREATE OR REPLACE TYPE WM_CONCAT_IMPL AS OBJECT

(

STR VARCHAR2(32767), 

STATIC FUNCTION ODCIAGGREGATEINITIALIZE(cs_ctx IN OUT WM_CONCAT_IMPL) RETURN NUMBER,    

MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL,PT IN VARCHAR2) RETURN NUMBER,

MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN WM_CONCAT_IMPL,RETURNVALUE OUT VARCHAR2,FLAGS IN NUMBER)RETURN NUMBER,

MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL,cs_ctx2 IN WM_CONCAT_IMPL) RETURN NUMBER

);

(2) 创建函数主体

CREATE OR REPLACE TYPE BODY WM_CONCAT_IMPL

IS

STATIC FUNCTION ODCIAGGREGATEINITIALIZE(cs_ctx IN OUT WM_CONCAT_IMPL)

RETURN NUMBER

IS

BEGIN

cs_ctx := WM_CONCAT_IMPL(NULL) ;

RETURN ODCICONST.SUCCESS;

END;

MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT WM_CONCAT_IMPL,PT IN VARCHAR2)

RETURN NUMBER

IS

BEGIN

IF(STR IS NOT NULL) THEN

STR := STR || ',' || PT;

ELSE

STR := PT;

END IF;

RETURN ODCICONST.SUCCESS;

END;

MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN WM_CONCAT_IMPL,RETURNVALUE OUT VARCHAR2,FLAGS IN NUMBER)

RETURN NUMBER

IS

BEGIN

RETURNVALUE := STR ;

RETURN ODCICONST.SUCCESS;

END;

MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT WM_CONCAT_IMPL,cs_ctx2 IN WM_CONCAT_IMPL)

RETURN NUMBER

IS

BEGIN

IF(cs_ctx2.STR IS NOT NULL) THEN

SELF.STR := SELF.STR || ',' || cs_ctx2.STR ;

END IF;

RETURN ODCICONST.SUCCESS;

END;

END;

 

 

 

(3) 创建函数

CREATE OR REPLACE FUNCTION wm_concat(PT VARCHAR2)

RETURN VARCHAR2 AGGREGATE USING WM_CONCAT_IMPL; 

 

(4) 创建同义词

create public synonym WM_CONCAT_IMPL for sys.WM_CONCAT_IMPL;

create public synonym wm_concat for sys.wm_concat;

grant execute on WM_CONCAT_IMPL to public;

grant execute on wm_concat to public;

  vm_concat 函数自建完毕,感兴趣的同学可以试一试。

相关推荐