0

我需要在函数中返回一个游标:

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

我在这里做错了什么?

4

2 回答 2

1

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

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;

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

您的程序将变为

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;
于 2016-03-08T19:52:10.683 回答
0

请给出 的定义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;
  ...
于 2016-03-08T20:24:58.023 回答