将值传递给函数 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;
...
我需要 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;
...