Oracle SQL 函数 - 函数调用中的数据类型错误

Oracle SQL function - wrong data type in function call

我的程序包中有一个函数,用于将逗号分隔的 varchar2 输入拆分为行,即。 'one, two, three' 变成:

  1. 一个
  2. 两个
  3. 三个

我已将函数声明为:

function unpack_list(
  string_in in varchar2
) return result_str 
is
  result_rows result_str;
begin
  
  with temp_table as (
  SELECT distinct trim(regexp_substr(string_in, '[^,]+', 1, level)) str
  FROM (SELECT string_in FROM dual) t
  CONNECT BY instr(string_in, ',', 1, level - 1) > 0)
  
  select str bulk collect into result_rows from temp_table;
  
  RETURN result_rows;
  
end;

和 return 类型为:

type result_str is table of varchar2(100);

但是,像这样调用函数:

select * from unpack_list('one1, two2')

给出以下错误:

ORA-00902: Invalid datatype

知道是什么原因造成的吗?

您正在从 SQL 上下文中调用一个 PL/SQL 函数,该函数 returns 一个 PL/SQL 集合类型(均在您的包中定义)。你不能直接这样做。您可以从 PL/SQL 上下文调用该函数,将结果分配给相同类型的变量,但这不是您尝试使用它的方式。 db<>fiddle 显示你的 set-up,你的错误,它在 PL/SQL 块中工作。

您可以改为在模式级别声明类型,如@Littlefoot 所示:

create type result_str is table of varchar2(100);

并删除包定义,这会发生冲突;适用于 SQL 和 PL/SQL (db<>fiddle)。

或者如果您无法创建 schema-level 类型,您可以使用 built-in 类型:

function unpack_list(
  string_in in varchar2
) return sys.odcivarchar2list 
is
  result_rows sys.odcivarchar2list;
begin
  
  with temp_table as (
  SELECT distinct trim(regexp_substr(string_in, '[^,]+', 1, level)) str
  FROM (SELECT string_in FROM dual) t
  CONNECT BY instr(string_in, ',', 1, level - 1) > 0)
  
  select str bulk collect into result_rows from temp_table;
  
  RETURN result_rows;
  
end;

也适用于 SQL 和 PL/SQL (db<>fiddle)。

或者您可以使用流水线函数,您的 PL/SQL 集合类型为:

function unpack_list(
  string_in in varchar2
) return result_str pipelined
is
begin
  
  for r in (
    SELECT distinct trim(regexp_substr(string_in, '[^,]+', 1, level)) str
    FROM (SELECT string_in FROM dual) t
    CONNECT BY instr(string_in, ',', 1, level - 1) > 0)
  loop
    pipe row (r.str);
  end loop;

  RETURN;

end;

适用于 SQL,或适用于 PL/SQL 内的 SQL 运行,但不能直接赋值给集合变量 (db<>fiddle)。

您采用哪种方法取决于您真正需要如何调用该函数。可能存在一些性能差异,但除非重复和密集调用它们,否则您可能不会注意到它们。

前面已经描述了错误的原因,所以我将post另一种可能的解决方案。对于 Oracle 19c(版本 19.7)及更高版本,您可以跳过 table 类型的创建并使用 SQL_MACRO 添加。返回的查询将集成到主查询中。

create function unpack_list (
  string_in varchar2
)
return clob
sql_macro(table)
is
begin
  
  return q'[
    select distinct
      trim(regexp_substr(
        unpack_list.string_in,
        '[^,]+', 1, level
      )) as str
    from dual
    connect by
      instr(
        unpack_list.string_in,
        ',', 1, level - 1
      ) > 0
  ]';
  
end;
/
select *
from unpack_list(
  string_in => 'one,two'
)
| STR |
| :-- |
| one |
| two |

db<>fiddle here