When I try to use WMSYS.WM_CONCAT with Oracle XE 10g, I receive a compilation error: ORA-00904: "WMSYS"."WM_CONCAT": invalid identifier
. Can anyone verify that this is indeed due to XE lacking this (undocumented) feature? If so, is there anyway to enable it in XE?
Asked
Active
Viewed 1.2k times
3

Lalit Kumar B
- 47,486
- 13
- 97
- 124

Stephen Swensen
- 22,107
- 9
- 81
- 136
3 Answers
3
Source: link.
Just create this function by yourself:
CREATE OR REPLACE TYPE wm_concat_impl
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
);
/
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;
/

smnbbrv
- 23,502
- 9
- 78
- 109
3
It is recommended not to use WM_CONCAT since it is an undocumented feature and it has been removed from 12c version. See Why not use WM_CONCAT function in Oracle?
If you are on 11gR2 and up, use LISTAGG.
For version prior to 11g where LISTAGG
is not supported, you could use ROW_NUMBER() and SYS_CONNECT_BY_PATH functions.
For example,
SELECT deptno,
LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,','))
KEEP (DENSE_RANK LAST ORDER BY curr),',') AS employees
FROM (SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) AS curr,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS prev
FROM emp)
GROUP BY deptno
CONNECT BY prev = PRIOR curr AND deptno = PRIOR deptno
START WITH curr = 1;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.

Lalit Kumar B
- 47,486
- 13
- 97
- 124
3
I had found a couple reference sites, but had no luck enabling it. I ended up writing my own function to handle the concatenation.
CREATE or replace FUNCTION CONCAT_LIST( cur SYS_REFCURSOR, sep Varchar2 ) RETURN VARCHAR2 IS
ret VARCHAR2(32000);
tmp VARCHAR2(4000);
BEGIN
loop
fetch cur into tmp;
exit when cur%NOTFOUND;
if ret is null then
ret := tmp;
else
ret := ret || sep || tmp;
end if;
end loop;
RETURN ret; END;/
Then it can be called as
SELECT distinct CONCAT_LIST(CURSOR(SELECT id FROM test_table1), ',') test_table1 FROM dual

RandyB
- 31
- 2
-
1Thanks, I'm really curious as to whether this function can be enabled. The best alternative I found was the User-defined Aggregate Function here: http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php. I renamed the function from string_agg to wm_concat since then I can share stored procedures with my co-workers who have full oracle 10g (the method given in the article allows the same syntax you would use with the real wm_concat -- as long as you are not using scripts which fully qualify wm_concat with wm_sys) – Stephen Swensen Sep 05 '10 at 14:18
-
That is pretty slick. I have a couple of large queries that I am using this function. As soon as I am back in the office I will create the new one and check performance. This has me curious. Thanks! – RandyB Sep 05 '10 at 14:42
-
Cool, I'd love to hear your performance results when you're done. – Stephen Swensen Sep 06 '10 at 15:54
-
1I did some load testing on both functions, CONCAT_LIST and STRING_AGG and found I had to make one modification to my function. I forgot to close the cursor and I maxed out the allowed amount rather quickly. After making the change I created a query that grouped a set of 250 shops to their corresponding type. The CONCAT_LIST completed in 2.68 seconds and the STRING_AGG from oracle-base completed in 0.38 seconds and looks a lot cleaner. I have changed the few queries I had to reference this new function. Here I thought I could help you and you ended up helping me. THANKS! – RandyB Sep 16 '10 at 14:26