wmsys.wm_concat函数问题
概述
在日常工作中,一些客户对于wmsys.wm_concat函数使用的非常多,一些客户在升级到12c时会碰到这个问题。因为Oracle从版本12c开始,WMSYS.WM_CONCAT()函数已被标记为不推荐使用,并在版本19c中完全移除了。因此,在Oracle 19c及更高版本中,该函数不再可用。
WMSYS.WM_CONCAT()函数用于将多行数据连接成一个具有逗号分隔符的字符串。由于该函数在早期版本中广泛使用,但存在一些限制和潜在安全风险,因此Oracle决定不再支持该函数,并鼓励用户使用其他方法来实现类似的功能。因此推荐使用LISTAGG()函数。LISTAGG()函数提供了更安全、更强大的字符串连接功能,在Oracle 11g及更高版本中就能够用到。
但是一些客户因为业务系统存留问题还需要这个函数,下文展示如 何创建这个函数。
wm_concat函数创建
方法1
CREATE OR REPLACE TYPE WM_CONCAT_TYPE AS OBJECT
(
  total VARCHAR2(32767),
  STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT WM_CONCAT_TYPE) RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateIterate(self IN OUT WM_CONCAT_TYPE, value IN VARCHAR2) RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateTerminate(self IN WM_CONCAT_TYPE, returnValue OUT VARCHAR2, flags IN NUMBER) RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateMerge(self IN OUT WM_CONCAT_TYPE, ctx2 IN WM_CONCAT_TYPE) RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY WM_CONCAT_TYPE IS
  STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT WM_CONCAT_TYPE) RETURN NUMBER IS
  BEGIN
    sctx := WM_CONCAT_TYPE(NULL);
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateIterate(self IN OUT WM_CONCAT_TYPE, value IN VARCHAR2) RETURN NUMBER IS
  BEGIN
    self.total := self.total || ',' || value;
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateTerminate(self IN WM_CONCAT_TYPE, returnValue OUT VARCHAR2, flags IN NUMBER) RETURN NUMBER IS
  BEGIN
    returnValue := LTRIM(self.total, ',');
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateMerge(self IN OUT WM_CONCAT_TYPE, ctx2 IN WM_CONCAT_TYPE) RETURN NUMBER IS
  BEGIN
    self.total := self.total || ctx2.total;
    RETURN ODCIConst.Success;
  END;
END;
/
CREATE OR REPLACE TYPE BODY WM_CONCAT_TYPE IS
  STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT WM_CONCAT_TYPE) RETURN NUMBER IS
  BEGIN
    sctx := WM_CONCAT_TYPE(NULL);
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateIterate(self IN OUT WM_CONCAT_TYPE, value IN VARCHAR2) RETURN NUMBER IS
  BEGIN
    self.total := self.total || ',' || value;
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateTerminate(self IN WM_CONCAT_TYPE, returnValue OUT VARCHAR2, flags IN NUMBER) RETURN NUMBER IS
  BEGIN
    returnValue := LTRIM(self.total, ',');
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateMerge(self IN OUT WM_CONCAT_TYPE, ctx2 IN WM_CONCAT_TYPE) RETURN NUMBER IS
  BEGIN
    self.total := self.total || ctx2.total;
    RETURN ODCIConst.Success;
  END;
END;
/
方法2
改版本的函数,拼接的内容是以varchar2(32767 )数据类型的文本形式保存。
一.解锁wmsys用户
alter user wmsys identified by "XXXXXX" account unlock;
-- 创建包、包体和函数
以wmsys用户登录数据库,执行下面的命令
CREATE 
	OR REPLACE TYPE WM_CONCAT_IMPL AS OBJECT -- AUTHID CURRENT_USER AS OBJECT
	(
		CURR_STR VARCHAR2 ( 32767 ),
		STATIC FUNCTION ODCIAGGREGATEINITIALIZE ( SCTX IN OUT WM_CONCAT_IMPL ) RETURN NUMBER,
		MEMBER FUNCTION ODCIAGGREGATEITERATE ( SELF IN OUT WM_CONCAT_IMPL, P1 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, SCTX2 IN WM_CONCAT_IMPL ) RETURN NUMBER 
	);
/  
  
-- 定义类型body:  
CREATE 
	OR REPLACE TYPE BODY WM_CONCAT_IMPL IS STATIC FUNCTION ODCIAGGREGATEINITIALIZE ( SCTX IN OUT WM_CONCAT_IMPL ) RETURN NUMBER IS BEGIN
		SCTX := WM_CONCAT_IMPL ( NULL );
	RETURN ODCICONST.SUCCESS;
	
END;
MEMBER FUNCTION ODCIAGGREGATEITERATE ( SELF IN OUT WM_CONCAT_IMPL, P1 IN VARCHAR2 ) RETURN NUMBER IS BEGIN
	IF
		( CURR_STR IS NOT NULL ) THEN
			CURR_STR := CURR_STR || ',' || P1;
		ELSE CURR_STR := P1;
		
	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 := CURR_STR;
	RETURN ODCICONST.SUCCESS;
	
END;
MEMBER FUNCTION ODCIAGGREGATEMERGE ( SELF IN OUT WM_CONCAT_IMPL, SCTX2 IN WM_CONCAT_IMPL ) RETURN NUMBER IS BEGIN
	IF
		( SCTX2.CURR_STR IS NOT NULL ) THEN
			SELF.CURR_STR := SELF.CURR_STR || ',' || SCTX2.CURR_STR;
		
	END IF;
	RETURN ODCICONST.SUCCESS;
	
END;
END;
/  
-- 自定义行变列函数:  
CREATE 
	OR REPLACE FUNCTION wm_concat ( P1 VARCHAR2 ) RETURN VARCHAR2 AGGREGATE USING WM_CONCAT_IMPL;
/  
-- 创建同义词并授权:
[sql] view plain copy
create public synonym WM_CONCAT_IMPL for wmsys.WM_CONCAT_IMPL;  
/  
create public synonym wm_concat for wmsys.wm_concat; 
/  
grant execute on WM_CONCAT_IMPL to public;  
/  
grant execute on wm_concat to public;  
/  
方法3
--	该版本的函数,拼接的内容是以clob (4G )数据类型的文本形式保存。
alter user wmsys identified by "Test_2017" account unlock;
-- 创建包、包体和函数:
以wmsys用户登录数据库,执行下面的命令
CREATE 
	OR REPLACE TYPE wm_concat_impl AUTHID CURRENT_USER AS OBJECT (
		CURR_STR VARCHAR2 ( 32767 ),
		CURR_STR_C CLOB,
		STATIC FUNCTION ODCIAGGREGATEINITIALIZE ( SCTX IN OUT WM_CONCAT_IMPL ) RETURN NUMBER,
		MEMBER FUNCTION ODCIAGGREGATEITERATE ( SELF IN OUT WM_CONCAT_IMPL, P1 VARCHAR2 ) RETURN NUMBER,
		MEMBER FUNCTION ODCIAGGREGATETERMINATE ( SELF WM_CONCAT_IMPL, RETURNVALUE OUT CLOB, FLAGS NUMBER ) RETURN NUMBER,
		MEMBER FUNCTION ODCIAGGREGATEMERGE ( SELF IN OUT WM_CONCAT_IMPL, SCTX2 WM_CONCAT_IMPL ) RETURN NUMBER 
	);
/
-- 定义类型body:  
CREATE 
	OR REPLACE TYPE BODY wm_concat_impl IS STATIC FUNCTION ODCIAGGREGATEINITIALIZE ( SCTX IN OUT WM_CONCAT_IMPL ) RETURN NUMBER IS BEGIN
		SCTX := WM_CONCAT_IMPL ( NULL, NULL );
	RETURN ODCICONST.SUCCESS;
	
END;
MEMBER FUNCTION ODCIAGGREGATEITERATE ( SELF IN OUT WM_CONCAT_IMPL, P1 VARCHAR2 ) RETURN NUMBER IS BEGIN
	IF
		(
			CURR_STR_C IS NULL 
			AND ( CURR_STR IS NULL OR LENGTH( CURR_STR )< 29950 )) THEN
		IF
			( CURR_STR IS NOT NULL ) THEN
				CURR_STR := CURR_STR || ',' || P1;
			ELSE CURR_STR := P1;
			
		END IF;
		ELSE
		IF
			( CURR_STR_C IS NULL ) THEN
				CURR_STR_C := CURR_STR;
			CURR_STR := NULL;
			
		END IF;
		CURR_STR_C := CURR_STR_C || ',' || P1;
		
	END IF;
	RETURN ODCICONST.SUCCESS;
	
END;
MEMBER FUNCTION ODCIAGGREGATETERMINATE ( SELF WM_CONCAT_IMPL, RETURNVALUE OUT CLOB, FLAGS NUMBER ) RETURN NUMBER IS BEGIN
	IF
		( CURR_STR IS NOT NULL ) THEN
			RETURNVALUE := CURR_STR;
		ELSE RETURNVALUE := CURR_STR_C;
		
	END IF;
	RETURN ODCICONST.SUCCESS;
	
END;
MEMBER FUNCTION ODCIAGGREGATEMERGE ( SELF IN OUT WM_CONCAT_IMPL, SCTX2 WM_CONCAT_IMPL ) RETURN NUMBER IS BEGIN
	IF
		( SCTX2.CURR_STR IS NOT NULL ) THEN
			SELF.CURR_STR := SELF.CURR_STR || ',' || SCTX2.CURR_STR;
		
	END IF;
	RETURN ODCICONST.SUCCESS;
	
END;
END;
/
-- 自定义行变列函数:  
CREATE OR REPLACE FUNCTION wm_concat(P1 VARCHAR2)  
RETURN CLOB AGGREGATE USING WM_CONCAT_IMPL;
/  
-- 创建同义词并授权:
create public synonym WM_CONCAT_IMPL for wmsys.WM_CONCAT_IMPL;
create public synonym wm_concat for wmsys.wm_concat ;
grant execute on WM_CONCAT_IMPL to public;  
grant execute on wm_concat to public;   
/