How to hold negative value into pl/sql variable? - sql

I have a procedure, where i want to declare a variable as number.
This variable is calculated using different columns.
If the output of calculation is negative how can i hold that negative value into that variable? and I keep getting this error: ORA-06502: PL/SQL: numeric or value error: character to number conversion error
declare
out_put_sum number;
begin
with input as(
select x.id,x.name,sum(case when ... then abs(x.quantity) as running_total
from xxxxxx x, yyyyyy y
where ... )
select i.running_total into out_put_sum
from input i;
if out_put_sum > 0 then ...
else ...
end if;
end;

sum(case when......then abs(x.quantity)as
running_total
Here if you are using '-'||abs(x.quantity) to denote negative value then please refrain from doing so. It will create a String out of it. Use -1*abs(x.quantity) instead.

Related

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.

Has anybody created a Snowflake User Defined Function (SQL) that takes decimal numbers as arguments?

I am trying to create a SQL UDF that takes a decimal number as an argument but if I pass in a number with a different number of decimal places I get an error, even if the number has a smaller number of digits to the right of the decimal point.
Here is a example of the problem:
CREATE OR REPLACE TABLE EXAMPLE (
COL1 NUMBER(7,5)
);
INSERT INTO EXAMPLE VALUES (9.12),(10.467),(11.6),(12.01234);
CREATE OR REPLACE FUNCTION LESS_THAN(DATA1 NUMBER(7,5))
RETURNS TABLE (COL1 NUMBER(7,5))
as
$$
SELECT COL1 FROM EXAMPLE WHERE COL1 < DATA1
$$
;
select * from table(LESS_THAN(11.3)); --Error: SQL compilation error: error line 1 at position 20 Invalid argument types for function 'LESS_THAN': (NUMBER(3,1))
select * from table(LESS_THAN(9.85)); --Error: SQL compilation error: error line 1 at position 20 Invalid argument types for function 'LESS_THAN': (NUMBER(3,2))
select * from table(LESS_THAN(10.85001)); --Works
I would like to be able to create a UDF that allows any decimal to be accepted.
Any thoughts?
Thanks
Try casting the inputs to NUMBER(7,5). For example:
select * from table(LESS_THAN('11.3'::NUMBER(7,5)));
select * from table(LESS_THAN( 11.3 ::NUMBER(7,5)));
You can use this system function to observe the types:
select 11.3 x, system$typeof(x); -- NUMBER(3,1)
select 11.30 x, system$typeof(x); -- NUMBER(3,1)
select 11.30 ::NUMBER(7,5) x, system$typeof(x); -- NUMBER(7,5)
select '11.30'::NUMBER(7,5) x, system$typeof(x); -- NUMBER(7,5)

How to have the variable be assigned 'null' if no results are being returned?

Currently have a variable called VALUE that needs to be assigned a numeric value so that the stored proc doesn't error out . Currently there is no data in the database for every hour so when it reaches a point where there is no data for the prior hour, the whole procedure errors out (since nothing is being returned). Is there a way I can have null assigned to VALUE if no results are returned? Below is my 'SELECT INTO' code:
SELECT VALUE
INTO v_PRIOR__VALUE
FROM VALUE V
WHERE CODE = rCode
AND TIME = rTIME - 1/24;
Or, you could actually handle such a situation:
declare
v_prior__value value.value%type;
begin
SELECT VALUE
INTO v_PRIOR__VALUE
FROM VALUE V
WHERE CODE = rCode
AND TIME = rTIME - 1/24;
exception
when no_data_found then
null; -- v_prior_Value will remain NULL, as declared in the DECLARE section
when too_many_rows then
v_prior_Value := -1; -- this is just an example; you'd handle it the way you want
end;
If you are expecting 0 or one rows, then I think the simplest method is aggregation:
SELECT MAX(VALUE)
INTO v_PRIOR__VALUE
FROM VALUE V
WHERE CODE = rCode AND TIME = rTIME - 1/24;
An aggregation query with no GROUP BY (or HAVING) always returns exactly one row.

SQL MAX expression Function

In a SQL statement I need to select the expression as
SELECT maxValues AS MAX(MIN(100,x),50)
Where x is a result of another complex SQL query. Basically in the place of x I have another SQl select statement.
If I execute the above expression using select statement, I get the following error.
ERROR [42000] ERROR: 'maxValues as max(min(100,x),50)'
nullerror 'EXCEPT' or 'FOR' or 'INTERSECT' or 'ORDER' or 'UNION'
Any help is appreciated.
Use GREATEST and LEAST rather than MAX and MIN
GREATEST and LEAST give you the greatest and least values from a list of values whereas MAX and MIN give you the maximum and minimum values in a column.
You can use a transaction that declares a variable to transfer your value from one query to the next
DECLARE
V_X NUMBER;
V_RESULT NUMBER;
V_SQL_1 CLOB := "_QUERY 1_";
BEGIN
EXECUTE IMMEDIATE V_SQL_1 INTO V_X;
SELECT MAX(MIN(100,V_X),50) INTO V_RESULT FROM DUAL;
END
(This assumes oracle-SQL.)
I'd go with a CASE:
SELECT maxValues AS CASE when x > 100 then 100
when x < 50 then 50
else x end
(If supported... I don't know IBM Neteeza.)

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.