将值传递给函数 oracle 上的 IN 子句

Passing values to IN clause on a function oracle

我需要 return 函数内的游标:

CREATE OR REPLACE FUNCTION test_cursor (
   bigstring   IN   VARCHAR2
)
   RETURN cursor

IS
  row_test table_colors := table_colors(bigstring);
  c1 CURSOR;
BEGIN
   OPEN c1 FOR
      select * from cars where color IN (select column_value
                                    from table(row_test));

   RETURN c1;

END test_cursor;

table_colors 是:

create or replace type table_colors as table of varchar2(20);

但是当我测试它通过 blue, red, pink, white'blue', 'red', 'pink', 'white' 时总是抛出相同的错误

ORA-06502: PL/SQL; numeric or value error: character string buffer too small

这一行row table_colors := table_colors(bigstring);

我这里做错了什么?

问题是 bigstring 是单个标量值,可能恰好包含逗号和单引号而不是值列表。您需要解析字符串以提取数据元素。如果 bigstring 中的每个单独元素恰好是有效的 Oracle 标识符,您可以使用内置的 dbms_utility.comma_to_table 函数。但是,如果是我的系统,我会对自己的解析功能感到更自在。假设 bigstring 只是一个逗号分隔的列表,我会使用 Tom Kyte 的 str2tbl function

的一个版本
create or replace function str2tbl( p_str in varchar2 ) 
  return table_colors
as
  l_str   long default p_str || ',';
  l_n        number;
  l_data    table_colors := table_colors();
begin
  loop
    l_n := instr( l_str, ',' );
    exit when (nvl(l_n,0) = 0);
    l_data.extend;
    l_data( l_data.count ) := ltrim(rtrim(substr(l_str,1,l_n-1)));
    l_str := substr( l_str, l_n+1 );
  end loop;
  return l_data;
end;

现在,您也可以在单个 SQL 语句中使用正则表达式实际实现 str2tbl。这可能会更有效率。但是,我希望字符串解析在您的性能问题列表中排名靠后,因此我倾向于坚持可能可行的最简单的方法。

您的程序将变成

CREATE OR REPLACE FUNCTION test_cursor (
   bigstring   IN   VARCHAR2
)
   RETURN sys_refcursor
IS
  row_test table_colors := str2tbl(bigstring);
  c1 sys_refcursor;
BEGIN
   OPEN c1 FOR
      select * from cars where color IN (select column_value
                                           from table(row_test));

   RETURN c1;

END test_cursor;

请给出table_colors的定义。 table_colors(bigstring) 返回的值似乎与 table_colors.

的赋值不兼容

作为一种好的做法,非平凡值的初始化应该在 begin ... end 内部完成,而不是在定义部分。这使您可以捕获函数或过程中的错误,而不是错误向外级联。例如,而不是:

IS
  row_test table_colors := table_colors(bigstring);
 c1 CURSOR;
BEGIN ...

你应该使用

IS
  row_test table_colors;
  c1 CURSOR;
BEGIN
  row_test := row_test;
  ...