带有DISTINCT子句的WM_CONCAT - 编译包与独立查询问题

Rei*_*ius 5 oracle plsql oracle10g oracle-sqldeveloper

我正在编写一些使用WM_CONCAT函数的程序.当我运行此查询时:

SELECT WM_CONCAT(DISTINCT employee_id)
FROM   employee
WHERE  ROWNUM < 20;
Run Code Online (Sandbox Code Playgroud)

它工作正常.当我尝试在包函数或过程中编译相对相同的查询时,它会产生此错误:PL/SQL:ORA-30482:此函数不允许使用DISTINCT选项

FUNCTION fetch_raw_data_by_range
RETURN VARCHAR2 IS

    v_some_string VARCHAR2(32000);

BEGIN

    SELECT WM_CONCAT(DISTINCT employee_id)
    INTO   v_some_string
    FROM   employee
    WHERE  ROWNUM < 20;

    RETURN v_some_string;

END;
Run Code Online (Sandbox Code Playgroud)

我意识到WM_CONCAT没有得到官方支持,但有人可以解释为什么它可以作为DISTINCT的独立查询工作,但不能在包中编译吗?

Nag*_*agh 5

问题是WM_CONCAT是写在pl/sql上的存储过程.

有一个开放的bug#9323679:PL/SQL使用DISTINCT FAILS ORA-30482调用用户定义的AGGREGRATE函数.

像这样的问题的解决方法是使用动态sql.

所以如果你把你的查询包装好

EXECUTE IMMEDIATE '<your_query>';
Run Code Online (Sandbox Code Playgroud)

然后它应该工作.

但正如OldProgrammer已经建议的那样,你最好完全避免使用这个WM_CONCAT.


Dba*_*Dba 5

PL/SQL 不允许您distinct在聚合函数中使用,并且此问题表明 SQL 引擎和 PL/SQL 引擎不使用相同的解析器。

解决这个问题的方法之一是使用子查询,如下所示,

SELECT WM_CONCAT(employee_id)
INTO   v_some_string
FROM   (select DISTINCT employee_id
        FROM   employee)
WHERE  ROWNUM < 20;
Run Code Online (Sandbox Code Playgroud)

另一种解决方案是按照 Nagh 建议使用动态 SQL,

FUNCTION fetch_raw_data_by_range
RETURN VARCHAR2 IS

    v_some_string VARCHAR2(32000);
    v_sql VARCHAR2(200);

BEGIN

    v_sql :='SELECT WM_CONCAT(DISTINCT employee_id)
             FROM   employee
             WHERE  ROWNUM < 20';

    execute immediate v_sql INTO v_some_string;
    RETURN v_some_string;
END;
Run Code Online (Sandbox Code Playgroud)