如何解决PLSQL ORA-06502
How to solve PLSQL ORA-06502
我有一个使用动态 sql 的小函数。我还需要动态 sql,因为我在存储过程运行期间获得了视图名称和 Where_clause。
create or replace FUNCTION Costs_MK(VIEWNAME IN VARCHAR2,
WHERE_Clause IN VARCHAR2)
RETURN VARCHAR2
IS
v_Costs VARCHAR2(3000);
BEGIN
EXECUTE IMMEDIATE 'Select Listagg(Costs, ' || '''' || ';' || '''' || ' )
WITHIN GROUP (ORDER BY Costs)
from (select distinct (Costs)
from ' || Viewname || ' where ' || where_Clause || ')'
INTO v_Costs;
dbms_output.put_line(length(v_Costs));
RETURN v_Costs;
END Costs_MK;
输出:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: in Line 9
1600
变量的长度是 1600 v_Costs,我已经将长度设置为 3000。但是我每次都会收到这个错误,我不知道我能做些什么来解决这个问题。
第 9 行是:
Line 8: BEGIN
Line 9:
Line 10: EXECUTE IMMEDIATE
匿名块:
DECLARE
VIEWNAME VARCHAR2(200);
WHERE_Clause VARCHAR2(200);
v_Return VARCHAR2(200);
BEGIN
VIEWNAME := 'Orders';
WHERE_BEDINGUNG := 'Orders.key like ' || '''' || ' B01 230/01/123456%' || '''';
v_Return := Costs_MK(
VIEWNAME => VIEWNAME,
WHERE_Clause => WHERE_Clause
);
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('v_Return = ' || v_Return);
*/
:v_Return := v_Return;
--rollback;
END;
现在我发现了错误。因为 v_Return VARCHAR2(200)
只有 200。如果我将它提高到 4000,我会得到想要的结果。好的,我想,我知道如何解决这个问题了。
尝试将 v_Costs
扩展到 4000。如果仍然收到错误,则问题是 LISTAGG 生成的字符串超过 4000(VARCHAR2 的最大长度)。
如果这是问题所在,您将需要使用 XMLAGG 或此问题中提供的解决方案之一:How to tweak LISTAGG to support more than 4000 character in select query?
您正在查看
的输出
dbms_output.put_line(length(v_Costs));
...所以您的函数正在达到那个点,因此不会在第 9 行(这是一个空行)或生成该输出之前的任何其他地方抛出异常。
因此一定是调用者得到了异常;调用函数的过程,或调用过程的匿名块。但不是函数本身。
根据显示的异常堆栈,它来自匿名块,因为过程或函数名称都不在该堆栈中(尽管您将过程名称排除在外是可行的)。匿名块的第 9 行必须分配一个对于变量来说太长的值,但这与该函数无关,除非您将返回的数字附加到一个字符串并且它太长了。
您的匿名块正在执行此操作:
DECLARE
...
v_Return VARCHAR2(200);
BEGIN
...
v_Return := Costs_MK(
VIEWNAME => VIEWNAME,
WHERE_Clause => WHERE_Clause
);
所以在第 9 行,您试图将您知道的 1600 个字符的值分配给您声明为 200 个字符的变量;因此错误。更改 v_Return
的声明以匹配函数变量的大小(或将它们都设为 4000 以允许更多开销)。
我有一个使用动态 sql 的小函数。我还需要动态 sql,因为我在存储过程运行期间获得了视图名称和 Where_clause。
create or replace FUNCTION Costs_MK(VIEWNAME IN VARCHAR2,
WHERE_Clause IN VARCHAR2)
RETURN VARCHAR2
IS
v_Costs VARCHAR2(3000);
BEGIN
EXECUTE IMMEDIATE 'Select Listagg(Costs, ' || '''' || ';' || '''' || ' )
WITHIN GROUP (ORDER BY Costs)
from (select distinct (Costs)
from ' || Viewname || ' where ' || where_Clause || ')'
INTO v_Costs;
dbms_output.put_line(length(v_Costs));
RETURN v_Costs;
END Costs_MK;
输出:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: in Line 9
1600
变量的长度是 1600 v_Costs,我已经将长度设置为 3000。但是我每次都会收到这个错误,我不知道我能做些什么来解决这个问题。
第 9 行是:
Line 8: BEGIN
Line 9:
Line 10: EXECUTE IMMEDIATE
匿名块:
DECLARE
VIEWNAME VARCHAR2(200);
WHERE_Clause VARCHAR2(200);
v_Return VARCHAR2(200);
BEGIN
VIEWNAME := 'Orders';
WHERE_BEDINGUNG := 'Orders.key like ' || '''' || ' B01 230/01/123456%' || '''';
v_Return := Costs_MK(
VIEWNAME => VIEWNAME,
WHERE_Clause => WHERE_Clause
);
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('v_Return = ' || v_Return);
*/
:v_Return := v_Return;
--rollback;
END;
现在我发现了错误。因为 v_Return VARCHAR2(200)
只有 200。如果我将它提高到 4000,我会得到想要的结果。好的,我想,我知道如何解决这个问题了。
尝试将 v_Costs
扩展到 4000。如果仍然收到错误,则问题是 LISTAGG 生成的字符串超过 4000(VARCHAR2 的最大长度)。
如果这是问题所在,您将需要使用 XMLAGG 或此问题中提供的解决方案之一:How to tweak LISTAGG to support more than 4000 character in select query?
您正在查看
的输出dbms_output.put_line(length(v_Costs));
...所以您的函数正在达到那个点,因此不会在第 9 行(这是一个空行)或生成该输出之前的任何其他地方抛出异常。
因此一定是调用者得到了异常;调用函数的过程,或调用过程的匿名块。但不是函数本身。
根据显示的异常堆栈,它来自匿名块,因为过程或函数名称都不在该堆栈中(尽管您将过程名称排除在外是可行的)。匿名块的第 9 行必须分配一个对于变量来说太长的值,但这与该函数无关,除非您将返回的数字附加到一个字符串并且它太长了。
您的匿名块正在执行此操作:
DECLARE
...
v_Return VARCHAR2(200);
BEGIN
...
v_Return := Costs_MK(
VIEWNAME => VIEWNAME,
WHERE_Clause => WHERE_Clause
);
所以在第 9 行,您试图将您知道的 1600 个字符的值分配给您声明为 200 个字符的变量;因此错误。更改 v_Return
的声明以匹配函数变量的大小(或将它们都设为 4000 以允许更多开销)。