2010-08-18 7 views
3

Когда я пытаюсь использовать WMSYS.WM_CONCAT с Oracle XE 10g, я получаю ошибку компиляции: ORA-00904: "WMSYS"."WM_CONCAT": invalid identifier. Может ли кто-нибудь убедиться, что это действительно связано с тем, что XE не имеет этой (недокументированной) функции? Если да, есть ли способ включить его в XE?Использование WMSYS.WM_CONCAT с Oracle XE 10g

ответ

3

Я нашел пару ссылочных сайтов, но не повезло. В конце концов я написал свою собственную функцию для обработки конкатенации.

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;/ 

Тогда можно назвать

SELECT distinct CONCAT_LIST(CURSOR(SELECT id FROM test_table1), ',') test_table1 FROM dual

+1

Спасибо, я действительно интересно, может ли эта функция включена. Лучшей альтернативой, которую я нашел, была пользовательская функция агрегации: http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php. Я переименовал функцию из string_agg в wm_concat, с тех пор я могу поделиться хранимыми процедурами с моими сотрудниками, у которых есть полный оракул 10g (метод, приведенный в статье, позволяет использовать тот же синтаксис, который вы будете использовать с реальным wm_concat, - пока вы не используя скрипты, которые полностью соответствуют wm_concat с wm_sys) –

+0

Это довольно пятно. У меня есть несколько больших запросов, которые я использую для этой функции. Как только я вернусь в офис, я создам новый и проверю производительность. Мне это любопытно. Благодаря! – RandyB

+0

Прохладный, я бы хотел услышать ваши результаты, когда вы закончите. –

3

Источник: link.

Просто создать эту функцию самостоятельно:

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; 
/
2

Рекомендуется не использовать WM_CONCAT, так как это не документировано, и она была удалена из 12с версии. См Why not use WM_CONCAT function in Oracle?

Если вы на 11gR2 и выше, используйте LISTAGG.

Для версии до 11g где LISTAGG не поддерживается, вы можете использовать ROW_NUMBER() и SYS_CONNECT_BY_PATH функции.

Например,

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.