oracle中的LISTAGG是否处理数字数据类型

时间:2017-10-24 15:58:32

标签: oracle plsql

我的结果如下所示

I_KEY 
10001
10002
10003
10004
10005

我需要修改结果以将输出显示为

I_KEY
10001,10002,10003,10004,10005

我已经编写了oracle函数来返回聚合结果,如下所示,我的疑问是,LISTAGG是否会处理 NUMBER 类型的值?

create or replace 
FUNCTION GET_I_KEY(
 RETURN NUMBER
  IS
    TEST I_DETAILS.I_KEY%TYPE;
  BEGIN
    SELECT LISTAGG(I_KEY, ',') WITHIN GROUP (ORDER BY I_KEY)
    INTO TEST
    FROM I_DETAILS 
RETURN TEST;
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
    TEST := NULL;
    RETURN TEST;
  END;

更新功能

create or replace 
FUNCTION GET_I_KEY(
IN I_DETAILS.I_NAME%TYPE)
RETURN VARCHAR2
IS
  TEST VARCHAR2(4000);
BEGIN
  SELECT LISTAGG(I_KEY, ',') WITHIN GROUP (ORDER BY I_KEY)
  INTO TEST
  FROM I_DETAILS ID ,I_TYPE IT
  WHERE ID.I_KEY = IT.I_KEY
  AND ID.I_NAME = IN;
RETURN TEST;
END;

1 个答案:

答案 0 :(得分:3)

来自the documentation

  

该函数的参数遵循以下规则:

     
      
  • measure_expr可以是任何表达式。度量列中的空值将被忽略。   ...
  •   
     

如果度量列为RAW,则返回数据类型为RAW;否则返回值为VARCHAR2。

measure_expr ,在这种情况下,您的I_KEY列可以是数字。 (数值将隐式转换为字符串)。结果不能是数字 - 因为您没有传递RAW数据,它将是VARCHAR

您发布的功能存在语法错误,您可能在发布时引入了这些错误,但由于您已将TEST声明为数字,因此修正后会出现运行时错误(通过%TYPE语法)。

create or replace 
FUNCTION GET_I_KEY
 RETURN NUMBER
  IS
    TEST I_DETAILS.I_KEY%TYPE;
  BEGIN
    SELECT LISTAGG(I_KEY, ',') WITHIN GROUP (ORDER BY I_KEY)
    INTO TEST
    FROM I_DETAILS;
RETURN TEST;
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
    TEST := NULL;
    RETURN TEST;
  END;
/

Function GET_I_KEY compiled

select get_i_key from dual;

ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "MY_SCHEMA.GET_I_KEY", line 6

您需要将TEST和函数返回类型声明为字符串。您也不需要异常处理程序 - listagg()是一个聚合函数,因此它永远不会返回任何行;由于没有group-by子句,它总是会返回1行,如果没有数据则为null。

create or replace 
FUNCTION GET_I_KEY
RETURN VARCHAR2
IS
  TEST VARCHAR2(4000);
BEGIN
  SELECT LISTAGG(I_KEY, ',') WITHIN GROUP (ORDER BY I_KEY)
  INTO TEST
  FROM I_DETAILS;

  RETURN TEST;
END;
/

Function GET_I_KEY compiled

select get_i_key from dual;

GET_I_KEY                               
----------------------------------------
10001,10002,10003,10004,10005

如果原始数据中有重复值,并且想要从结果中删除它们,则可以使用子查询;将函数内的查询更改为:

  SELECT LISTAGG(I_KEY, ',') WITHIN GROUP (ORDER BY I_KEY)
  INTO TEST
  FROM (
    SELECT DISTINCT I_KEY
    FROM I_DETAILS
  );

或修改后的函数使用相同的模式:

create or replace 
FUNCTION GET_I_KEY(
  IN I_DETAILS.I_NAME%TYPE)
RETURN VARCHAR2
IS
  TEST VARCHAR2(4000);
BEGIN
  SELECT LISTAGG(I_KEY, ',') WITHIN GROUP (ORDER BY I_KEY)
  INTO TEST
  FROM (
    SELECT DISTINCT IT.I_KEY
    FROM I_DETAILS ID
    JOIN I_TYPE IT
    ON IT.I_KEY = ID.I_KEY
    WHERE ID.I_NAME = IN
  );

  RETURN TEST;
END;
/

虽然加入似乎毫无意义 - 您可以只查询I_DETAILS,除非您有孤儿关键值,这些关键值不会出现在I_TYPE中,并且您试图将其排除在外。