ORA-06502: PL/SQL: numeric or value error when concatenating - sql

DECLARE
a NUMBER;
b NUMBER;
BEGIN
a :=: a;
b :=: b;
DBMS_OUTPUT.PUT_LINE('sum = '|| a+b);
END;
I am getting error as numeric or value error

The problem is with operator precedence:
Oracle evaluates operators with equal precedence from left to right within an expression.
... and as the table shows + and || have equal precedence. So in this statement:
DBMS_OUTPUT.PUT_LINE('sum = '|| a+b);
this is interpreted as 'sum = '|| a which gives you a string, then <result string> + b, and string + number will cause the error you see if the string cannot be implicitly converted to a number - and 'sum = 1' can't be.
You can add parentheses to override the default precedence:
DBMS_OUTPUT.PUT_LINE('sum = '|| (a+b));
db<>fiddle

A simplified version to clarify the issue:
begin
dbms_output.put_line('Result ' || 2 + 2);
end;
/
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 2
This fails because the expression is built left to right, and you can't add 2 to the string 'Result: 2'.
It would work with multiplication or division, because arithmetic precedence causes those operations to be evaluated first.
begin
dbms_output.put_line('Result ' || 2 / 2);
end;
/
Result 1
PL/SQL procedure successfully completed.
To allow this to work for any operation, you need to bracket the expression:
begin
dbms_output.put_line('Result ' || (2 + 2));
end;
/
Result 4
PL/SQL procedure successfully completed.
Just to add, it is clearer to write host/bind variables without any space after :, for example :myvar rather than : myvar.

You're not seeing a sqldeveloper error, you're getting an error running a sql statement in sqldeveloper, that is something very different.
For simplicity I'm declaring the variables in my example instead of using bind variables like you do:
DECLARE
a NUMBER;
b NUMBER;
BEGIN
a := 1;
b := 2;
DBMS_OUTPUT.PUT_LINE('sum = '||a+b);
END;
Returns
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 7
The important information is the "line 7". Something is failing in that dbms_output statement and the cause is the operator precedence. Best is to tell the database engine that you want the number concatenated to the string, the error indicates that there is an implicit conversion happening.
The following works just fine:
DECLARE
a NUMBER;
b NUMBER;
BEGIN
a := 1;
b := 2;
DBMS_OUTPUT.PUT_LINE('sum = '|| TO_NUMBER(a+b));
END;
One additional remark. This syntax
a :=: a;
works but is very confusing. I would use a more descriptive name for your bind variable and separate the assignment operator := from the bind variable. Writing it like this is a lot more readable:
a := :variablea;

Related

When I am using listagg in procedure I am getting plsql numeric or value error

Ora-06502: pl/SQL: numeric or value error.
select listagg(listagg(l_comb,';') within group (order by rownum) as l_comb into out_output_string
From (select product_id|| ':' || rule_group as l_comb from dt1 ).
My expected output for example - 1234:12;456:23
If your out_output_string parameter is type VARCHAR2 and it is used in a SQL statement, the parameter will return a string up to the length of
4000 characters (11g and earlier) or MAX_STRING_SIZE (12c and above).
Your error is occurring because a local variable in a separate PL/SQL procedure is too small. See How to fix Character string buffer too small error in OUT variable in Stored Procedure
I would recommend adding an EXCEPTION block in the ADD_LIST procedure. Use UTL_CALL_STACK to trace the program flow. Follow the stack trace to find the variable that is sized too small.
Sample package
CREATE OR REPLACE PACKAGE test_pkg
AS
pkg_ten_chars VARCHAR2(10); -- pkg_variable that is too small
PROCEDURE add_list(out_output_string OUT VARCHAR2);
PROCEDURE add_list_passthrough(out_output_string2 OUT VARCHAR2);
END test_pkg;
CREATE OR REPLACE PACKAGE BODY test_pkg
AS
PROCEDURE add_list(out_output_string OUT VARCHAR2)
IS
BEGIN
WITH dt1
AS
(select 1234 product_id, 12 rule_group from dual
UNION
select 456 product_id, 23 rule_group from dual
)
SELECT LISTAGG(product_id|| ':' || rule_group, ';') WITHIN GROUP (ORDER BY ROWNUM)
INTO out_output_string -- return variable can be up to MAX_STRING_SIZE of SQL statement
FROM dt1;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('[how code got here - ' || SQLERRM || ']');
-- start at depth = 2 because depth = 1 will be the line below
FOR d in 2 .. utl_call_stack.dynamic_depth() LOOP
dbms_output.put_line('Depth: ' || d
|| ', Procedure: ' || utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(d))
|| ', Line: '|| to_char(utl_call_stack.unit_line(d))
);
END LOOP;
END add_list;
PROCEDURE add_list_passthrough(out_output_string2 OUT VARCHAR2)
IS
BEGIN
add_list(test_pkg.pkg_ten_chars); -- (line=33) errors b/c package variable is too small
out_output_string2 := test_pkg.pkg_ten_chars;
END add_list_passthrough;
END test_pkg;
Using an anonymous PL/SQL block to call the different procedures.
DECLARE
l_local_max_chars VARCHAR2(4000); -- local variable of max characters
l_local_ten_chars VARCHAR2(10); -- local variable of ten characters
BEGIN
test_pkg.add_list_passthrough(l_local_max_chars); -- (line=5) errors in add_list_passthrough
test_pkg.add_list(l_local_max_chars); -- OK
test_pkg.add_list(l_local_ten_chars); -- (line=7) errors b/c local variable too small
END;
Results
[how code got here - ORA-06502: PL/SQL: numeric or value error]
Depth: 2, Procedure: TEST_PKG.ADD_LIST_PASSTHROUGH, Line: 33
Depth: 3, Procedure: __anonymous_block, Line: 5
[how code got here - ORA-06502: PL/SQL: numeric or value error]
Depth: 2, Procedure: __anonymous_block, Line: 7

Is it possible to have constant function parameters in SQL?

Is it possible to have constant function parameters in SQL to make sure the values are not changed later?
Something like this doesn't work:
function my_func(
first_param constant varchar2
, second_param constant varchar2
) return varchar2
is
... -- Rest
That is not necessary as you cannot redefine an IN parameter. For example:
CREATE FUNCTION does_not_work(
a IN NUMBER,
b IN NUMBER
) RETURN NUMBER
IS
BEGIN
IF a < 2 THEN
a := 2;
END IF;
RETURN GREATEST( a, b );
END;
/
(Note: the IN keyword is optional and the default parameter direction; you would get the same error if you declared the signature without the IN keywords.)
Gives:
ORA-24344: success with compilation error
If you look at the errors:
SELECT * FROM USER_ERRORS;
Outputs:
NAME
TYPE
SEQUENCE
LINE
POSITION
TEXT
ATTRIBUTE
MESSAGE_NUMBER
DOES_NOT_WORK
FUNCTION
1
8
5
PLS-00363: expression 'A' cannot be used as an assignment target
ERROR
363
DOES_NOT_WORK
FUNCTION
2
8
5
PL/SQL: Statement ignored
ERROR
0
This tells you that you can't use an IN parameter as an assignment target.

Assigning a string value to a variable of type NUMBER in pl/sql procedure not throwing any error

I have started working on pl/sql recently. So still not very clear with the concepts. I am a writing a Stored procedure which has some input values.
using thses input values as keys,i create a cursor.
After this i iterate through the cursor output , and call insert statement for each row fetched.
before calling the insert, i am doing few data manipulations.
Splitting a String '4564:0:75556' considering : as the delimiter.
For this i am using SUBSTR and INSTR functions
My actual question starts here.
The output of SUBSTR will be a string value. i am assigning this value to a variable of type NUMBER which i declared in the proc.
I was expecting an error while compiling this proc or atleast when i test it.
Strangely i didnt get any error, the proc works fine.
is this the expected behaviour?
Can we assign a string value to variable of type NUMBER?
in my proc i am assignin output of SUBSTR to variables d_c1_subscr_no, d_c1_account_no, d_c1_subscr_no_resets NUMBER
My Stored proc:
CREATE OR REPLACE PROCEDURE P4_UPDATE_BILL_PERIOD_BULK(oldperiod IN VARCHAR,
newperiod IN VARCHAR,
accountno IN VARCHAR) IS
d_c1_subscr_no NUMBER;
d_c1_account_no NUMBER;
d_c1_subscr_no_resets NUMBER;
d_first_occ NUMBER;
d_second_occ NUMBER;
CURSOR c1_active_subs IS
select ciem.external_id as occ_ext_id,
ciem.subscr_no as fx_subscr_no,
ciem.subscr_no_resets as fx_subscr_no_resets
from customer_id_equip_map ciem, service s
where ciem.subscr_no = s.subscr_no
AND s.parent_account_no = to_number(accountno)
AND ciem.subscr_no_resets = s.subscr_no_resets
AND ciem.external_id_type = 6
AND ciem.active_date < SYSDATE
AND (ciem.inactive_date is null or ciem.inactive_date > SYSDATE);
d_subscriber c1_active_subs%ROWTYPE;
BEGIN
OPEN c1_active_subs;
LOOP
FETCH c1_active_subs
into d_subscriber;
EXIT WHEN c1_active_subs%NOTFOUND;
IF c1_active_subs%FOUND THEN
d_first_occ := INSTR(d_subscriber.occ_ext_id, ':', 1, 1);
d_second_occ := INSTR(d_subscriber.occ_ext_id, ':', 1, 2);
d_c1_subscr_no := SUBSTR(d_subscriber.occ_ext_id,
1,
d_first_occ - 1);
d_c1_subscr_no_resets := SUBSTR(d_subscriber.occ_ext_id,
d_first_occ + 1,
d_second_occ - d_first_occ - 1);
d_c1_account_no := SUBSTR(d_subscriber.occ_ext_id,
d_second_occ + 1);
INSERT INTO P4_BULK_DATA
(BATCH_ID, STATUS, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8)
VALUES
(10300,
0,
accountno,
d_subscriber.fx_subscr_no,
d_subscriber.fx_subscr_no_resets,
d_c1_account_no,
d_c1_subscr_no,
d_c1_subscr_no_resets,
oldperiod,
newperiod);
END IF;
END LOOP;
CLOSE c1_active_subs;
END;
Oracle database will normally conduct implicit conversions between many data types. As clarified in the link provided in the comment, Oracle implicitly converts from VARCHAR2 to NUMBER and vise versa. That said, it is always not recommended approach to rely on Oracle implicit conversions. It is always better to use the rich library of conversion functions provided by Oracle. For example:
Using the concatenation operator (||) to concatenate a string and an arithmetic expression can produce an error, which you can prevent by using the TO_CHAR function to convert the arithmetic expression to a string before concatenation
Relying on language settings in the database for the format of a DATE value can produce unexpected results, which you can prevent by using the TO_CHAR function and specifying the format that you want

SQL: How to get substring from function output in sql?

IN one of My Application. We have one query, where actully we are calling a function and function returns o/p as String. Any one have idea how to get substring from function returned o/p?
I am using like this
select substr(myfunction(),0,4000) from dual.
I am getting below issue.
ORA-06502: PL/SQL: numeric or value error: character string buffer too
small.
Please help me . Thanks in Advance.
Since you're applying a substr, presumably the value being returned by your function is greater than 4000 characters. If that's the case then you will get this error from SQL, you can't avoid it. It's trying to assign the long string value to an (implicit) SQL-level varchar2, which of course cannot be more than 4000 characters either, before passing that to the substr function.
You will have to add the substr to the return from your function, or if it is sometimes called from somewhere that can handle the long values, you can have a wrapper function that only returns the first 4000 characters - so you can have the appropriate value as needed.
To demonstrate with a dummy function to (inefficiently!) create a large string:
create or replace function myfunction(strlen number) return varchar2 is
str varchar2(32767) := 'X';
begin
while length(str) < least(strlen, 32767) loop
str := str || 'X';
end loop;
return str;
end myfunction;
/
This is fine because the function's output doesn't exceed the SQL varchar2 size:
select length(substr(myfunction(4000),0,4000)) from dual;
LENGTH(SUBSTR(MYFUNCTION(4000),0,4000))
---------------------------------------
4000
But this gets your error because the function's output is too long:
select length(substr(myfunction(4001),0,4000)) from dual;
SQL Error: ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "STACKOVERFLOW.MYFUNCTION", line 7
06502. 00000 - "PL/SQL: numeric or value error%s"
With a simple wrapper function as a workaround:
create or replace function trunc_myfunction(strlen number) return varchar2 is
begin
return substr(myfunction(strlen), 0, 4000);
end;
/
select length(substr(trunc_myfunction(4000),0,4000)) from dual;
LENGTH(SUBSTR(TRUNC_MYFUNCTION(4000),0,4000))
---------------------------------------------
4000
select length(substr(trunc_myfunction(4001),0,4000)) from dual;
LENGTH(SUBSTR(TRUNC_MYFUNCTION(4001),0,4000))
---------------------------------------------
4000
select length(substr(trunc_myfunction(32767),0,4000)) from dual;
LENGTH(SUBSTR(TRUNC_MYFUNCTION(32767),0,4000))
----------------------------------------------
4000
Most probably you are trying to store more characters than is allowed in one of the variables that you use in your function. See: PL/SQL: numeric or value error: character string buffer too small %ROWTYPE
Simplest example:
DECLARE
v_varchar2_test VARCHAR2(5);
BEGIN
v_varchar2_test := '123456';
END;
And the error is, like in your case, ORA-06502.
Make sure that the value returned by the function is of the correct type;
I have just tried it like this:
create or replace
FUNCTION MONTH
(DATA IN DATE)
RETURN VARCHAR IS
BEGIN
RETURN TO_CHAR(DATA, 'MM');
END;
and the call:
SELECT substr(MONTH(SYSDATE),0,1) FROM DUAL;
and it worked.

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

I tried the following code different ways, like by taking out the while or the if, but when I put both together (if and while), I always get the error at the end...
undefine numero
set serveroutput on
accept numero prompt 'Type # between 100 and 999: '
declare
i number:=1;
a char(25);
b char(1);
c varchar2(10);
d number;
begin
c := &numero;
d := length(c);
b := substr(c, i, 1);
while i <= d loop
if b = '1' then
a:= a||'one ';
end if;
i := i+1;
end loop;
dbms_output.put_line('The number is '||a);
end;
/
ERROR:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 13
06502. 00000 - "PL/SQL: numeric or value error%s"
FIXED by changing how I declared the variable "a" to:
a varchar2(2000);
*Notice that here, the significant change is to use VARCHAR2 instead of CHAR (not the bigger length). According to #user272735 's answer, that's the key.
PL/SQL: numeric or value error: character string buffer too small
is due to the fact that you declare a string to be of a fixed length (say 20), and at some point in your code you assign it a value whose length exceeds what you declared.
for example:
myString VARCHAR2(20);
myString :='abcdefghijklmnopqrstuvwxyz'; --length 26
will fire such an error
CHAR is a fixed-length data type that uses as much space as possible. So a:= a||'one '; will require more space than is available. Your problem can be reduced to the following example:
declare
v_foo char(50);
begin
v_foo := 'A';
dbms_output.put_line('length of v_foo(A) = ' || length(v_foo));
-- next line will raise:
-- ORA-06502: PL/SQL: numeric or value error: character string buffer too small
v_foo := v_foo || 'B';
dbms_output.put_line('length of v_foo(AB) = ' || length(v_foo));
end;
/
Never use char. For rationale check the following question (read also the links):
Oracle datatype: Should I use VARCHAR2 or CHAR
This may also happen if you have a faulty or accidental equation in your csv file.
i.e - One of the cells in your csv file starts with an equals sign (=) (An excel equation) which will, in turn throw an error.
If you fix, or remove this equation by getting rid of the equals sign, it should solve the ORA-06502 error.