I have oracle stored procedure where i check sender I'd,source system, and transaction number at the beginning of the procedure. Can I do it this way:
If Id != "aaa"
Exit -1;
Else if source = " ".
Exit -1;
Else if trans = " ".
Exit -1;
Else.
-- continues stored procedure
I appreciate any help
To rephrase your question more generally, you want a caller of your routine to know if something bad has happened inside it. There are (at least) three ways of doing this in PL/SQL.
Use an OUT parameter
Procedure cannot return a value, the way a function does, but it can set an output parameter:
CREATE PROCEDURE inner (p_id IN VARCHAR2(10), p_res OUT NUMBER)
IS
BEGIN
p_res := 0; -- default value
IF p_id = 'aaa' THEN
p_res := -1;
RETURN;
ELSE
-- do something
END IF;
END;
Then in the caller you would have:
DECLARE res NUMBER;
...
inner('aaa', res);
IF res = -1 THEN
-- panic!
END IF;
...
Use a function
Despite your seeming aversion to functions, this might be an option.
CREATE FUNCTION inner (p_id IN VARCHAR2(10))
RETURN NUMBER
IS
BEGIN
IF p_id = 'aaa' THEN
RETURN -1;
END IF;
-- do something
RETURN 0;
END;
Then in the caller:
...
IF inner('aaa') = -1 THEN
-- panic!
END IF;
...
Use an exception
Similar to other programming languages, PL/SQL has exceptions:
CREATE PROCEDURE inner (p_id IN VARCHAR2(10))
IS
BEGIN
IF p_id = 'aaa' THEN
RAISE_APPLICATION_ERROR(-20000, 'ID cannot be ''aaa''');
ELSE
-- do something
END IF;
END;
and in the caller:
...
DECLARE
panic EXCEPTION; -- declare exception
PRAGMA EXCEPTION_INIT (panic, -20000); -- assign error code to exception
...
BEGIN
inner ('aaa');
EXCEPTION
WHEN panic THEN
-- proceed to panic
END;
You are using a wrong syntax both for the IF...ELSE and for the exit.
Given that you are saying you need to get a return value, you probably need a function like this, using CASE:
create or replace function testFun ( pIn1 varchar2, pIn2 varchar2) return varchar2 is
begin
case
when pIn1 is null then
return -1;
when pIn2 = ' ' then
return -2;
else
return 999;
end case;
end;
Related
I want to write a procedure that logs output to the Oracle concurrent manager log when run from a concurrent program, but writes to dbms_output when run "standalone".
Is there a way from PL/SQL to check whether my code is being run from a concurrent request? The best way I've been able to find is
select * from fnd_concurrent_requests
where oracle_session_id = userenv('SESSIONID');
but that's pretty slow. Is there a function or table I can query that gives me the information more efficiently?
You can best use fnd_global.conc_request_id like we do in our blitz report code:
procedure write_log(p_text in varchar2, p_log_level in number default 1) is
begin
if fnd_global.conc_request_id>0 then
fnd_file.put_line(fnd_file.log,p_text);
else
fnd_log.string(p_log_level,'XXEN',p_text); --or your dbms_output.put_line() call
end if;
end write_log;
Add a boolean flag argument to the procedure that you can use to tell it where you want to log to when you call the procedure and then pass different flags from your two different (concurrent/non-concurrent) programs:
CREATE PROCEDURE my_proc(
i_value1 IN NUMBER,
i_use_concurrent_logging IN BOOLEAN DEFAULT FALSE
)
IS
-- Helper function so you only check the flag in one place.
PROCEDURE log(value IN VARCHAR2)
IS
BEGIN
IF i_use_concurrent_logging THEN
-- put your concurrent logging code here.
NULL;
ELSE
DBMS_OUTPUT.PUT_LINE(value);
END IF;
END;
BEGIN
-- Do stuff.
log('Stuff done');
-- Do other stuff
log('Other Stuff done');
END;
/
If you want to use your check once in the procedure then you could use:
CREATE OR REPLACE PROCEDURE my_proc(
i_value1 IN NUMBER
)
IS
v_use_concurrent_logging BOOLEAN := FALSE;
PROCEDURE log(value IN VARCHAR2)
IS
BEGIN
IF v_use_concurrent_logging THEN
-- put your concurrent logging code here.
NULL;
ELSE
DBMS_OUTPUT.PUT_LINE(value);
END IF;
END;
BEGIN
DECLARE
v_exists INT;
BEGIN
SELECT 1
INTO v_exists
FROM fnd_concurrent_requests
WHERE oracle_session_id = userenv('SESSIONID')
AND ROWNUM = 1;
v_use_concurrent_logging := TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_use_concurrent_logging := FALSE;
END;
-- Do stuff.
log('Stuff done');
-- Do other stuff
log('Other Stuff done');
END;
/
db<>fiddle here
I try to create the function login that takes customer number(pnr) and password from same table. Its fine to create function but test crashes with following eror:
ORA-00904: "P_PASSWD": invalid identifier
create or replace function logga_in(
p_pnr bankkund.pnr%type,
p_passwd bankkund.passwd%type
)
return number
as
v_resultat number(1);
begin
select count(pnr) into v_resultat
from bankkund
where p_pnr = pnr
and p_passwd = passwd;
return 1;
exception
when no_data_found then
return 0;
end;
There is one other problem with your code not suggested in the comments, A count function from a select into will not raise a NO_DATA_FOUND exception. You may use an IF condition on count or do something like this, which is preferable
CREATE OR REPLACE FUNCTION logga_in (
p_pnr bankkund.pnr%TYPE,
p_passwd bankkund.passwd%TYPE
) RETURN NUMBER AS
v_resultat NUMBER(1);
BEGIN
SELECT 1 --do not use count if you wish to handle no_data_found
INTO v_resultat FROM
bankkund WHERE pnr = p_pnr AND
passwd = p_passwd
AND ROWNUM = 1; --Add this
RETURN 1;
EXCEPTION
WHEN no_data_found THEN
RETURN 0;
END;
Now, as far as calling the procedure is concerned, there are various options available including using bind variable
VARIABLE p_pnr number --use the datatype of bankkund.pnr%TYPE
VARIABLE p_passwd VARCHAR2(10) --use the datatype of bankkund.passwd
SELECT logga_in(:p_pnr,:p_passwd) FROM dual;
Or substitution variable
SELECT logga_in('&p_pnr','&p_passwd') FROM dual;
Give inputs when prompted.
Or use PL/SQL block
DECLARE
v_res INT;
v_pnr bankkund.pnr%type := 12892; --or appropriate value
p_passwd bankkund.passwd%type := some_passwd';
BEGIN
v_res := logga_in();
If v_res = 1 THEN
do_something_u_want; --call or execute appropriate action.
END IF;
END;
/
I have this function and I need to compare number with varchar.
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return number as
begin
declare odd integer;
declare i_perecentage=0;
begin
if i_odd ='SP'
then
return (0);
end if;
odd:=round(to_number((1-i_perecentage/100)*i_odd),2);
if odd<1
then
return(i_odd);
else
return(round(odd,2));
end if;
end;
end;
/
PS: I edited function and i resolve problem with comparing , now i have another situation that i dont like..
This function returns calculated percentage of i_odd. The problem is that if i pass 0 in i_percentage in results i get result with no decimal places(for example: i_odd = 3.10 and i_percentage = 0 i get odd = 3 but if I pass i_odd = 3.10 and i_percentage = 1 i get odd = 3.10 ).
Why is on i_percentage = 0 i dont get decimal places ??
If you want to validate a varchar2 field as a number in PL/SQL, typically you'd just try converting it to a number and catch the exception.
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return number as
odd number;
BEGIN
-- if i_odd = 'SP' (or another non-number), this will throw an ORA-01722
-- exception which will be caught in the exception block, below
odd := to_number(i_odd); -- you might want a format mask here
--... now you can use "odd" as a number
EXCEPTION WHEN INVALID_NUMBER THEN
return 0;
END;
/
You can also nest a begin..end block in the middle of your code just to catch exceptions, if that works better for you:
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return number as
odd number;
begin
begin
odd := to_number(i_odd); -- you might want a format mask here
exception when INVALID_NUMBER then
odd := 0;
end;
--... now you can use "odd" as a number
end;
/
The reason why you can't catch the invalid_number exception is because you are declaring the input parameter as a number. When you call your function, Oracle tries to convert the string to a number first (and it fails of course, before entering your code at all).
If you change the input parameter to varchar2, then the conversions to number (implicit in this case) is done inside the function, and invalid numbers can be caught and handled as you want (here I'm just returning a different string to denote the issue):
create or replace function is_odd_even(i_num in varchar2)
return varchar2
is
begin
-- conversion to number is done here
if (mod(i_num, 2) = 0) then
return 'EVEN';
else
return 'ODD';
end if;
exception
when INVALID_NUMBER or VALUE_ERROR then
-- do something meaningful
return 'INV';
end;
Usage example:
with x as (
select '1' as val from dual
union all
select 'SP' as val from dual
union all
select '2' as val from dual
)
select x.val, is_odd_even(x.val)
from x;
Output:
1 ODD
SP INV
2 EVEN
SOLUTION:
CREATE OR REPLACE FUNCTION getOdds(i_odd in varchar2, i_id in number) return varchar2 as
odd varchar2(10);
ret_value number(4);
begin
if (i_odd ='SP') or i_odd is null then
return 'SP';
else
odd :=ROUND( TO_NUMBER( ( 1 - (play_beting.get_odds_percentage(i_id) / 100 ) ) * TO_NUMBER(i_odd) ), 2);
IF(odd < 1) THEN
ret_value := TO_NUMBER(i_odd);
ELSE
ret_value := to_char(odd,'9999.00');
END IF;
END IF;
RETURN to_char(ret_value,'9999.00');
END getOdds;
I am trying to generate DIVIDE_BY_ZERO exception in my oracle PL/SQL program. I using function but when I run my program I am getting error which is shown below. Can anyone tell me what is wrong in my program ?
code:
CREATE OR REPLACE
PACKAGE CALCULATOR AS
FUNCTION AddNumber(addend IN Number, Addend2 IN Number) RETURN NUMBER;
FUNCTION DivNumber(divend IN Number, divend2 IN Number) RETURN NUMBER;
END CALCULATOR;
/
CREATE OR REPLACE
PACKAGE BODY CALCULATOR AS
FUNCTION AddNumber(addend IN Number, Addend2 IN Number) RETURN NUMBER AS
BEGIN
return addend + addend2;
END AddNumber;
FUNCTION DivNumber(divend IN Number, divend2 IN Number) RETURN NUMBER AS
BEGIN
return divend / divend2;
EXCEPTION
WHEN ZERO_DIVIDE THEN
NULL;
END DivNumber;
END CALCULATOR;
/
select calculator.AddNumber(3,4) from dual;
select calculator.DivNumber(12,0) from dual;
output:
you can deal with exceptions like this
FUNCTION DivNumber(divend IN Number, divend2 IN Number) RETURN NUMBER AS
e_ZERO_DIVIDE EXCEPTION;
BEGIN
-- the condition
IF divend2 = 0 THEN
Raise e_ZERO_DIVIDE;
END IF;
return divend / divend2;
--Exception handling
EXCEPTION
WHEN e_ZERO_DIVIDE THEN
dbms_output.put_line('Division by 0 or null');
RETURN 1; -- or 0 or null
WHEN OTHERS THEN
dbms_output.put_line('ERROR: '||sqlerrm);
RETURN 1; -- or 0 or null
END DivNumber;
IMO you should never write code which throws an avoidable exception. There may be times when you can't avoid raising an exception but in this case you can. I suggest that you rewrite your function as follows:
FUNCTION DivNumber(numerator IN Number, denominator IN Number) RETURN NUMBER AS
BEGIN
IF NVL(denominator, 0) <> 0 THEN
return numerator / denominator;
ELSE
RETURN NULL;
END IF;
END DivNumber;
Best of luck.
CREATE PROCEDURE Pname(in_Tid IN VARCHAR2,in_IP IN VARCHAR2,outstaticip OUT VARCHAR2,outcount OUT NUMBER)
AS
BEGIN
select STATIC_IP into outstaticip from OP_TTER_MAPPING where TERMINAL_ID = in_Tid;
if in_IP = outstaticip then
return 1;
else
select COUNT(*) into outcount from OP_TTER_MAPPING where DYNAMIC_IP_LOW <= in_IP AND DYNAMIC_IP_HIGH >= in_IP AND TERMINAL_ID = in_Tid;
if outcount = 1 then
return 1;
else
return 0;
end if;
end if;
END;
Is it possible to use return in stored procedure like above?
If we can use return, how can i get that return value in Executesql("begin Pname(----)END") method
EDIT
Now I edited my return value in stored procedure like this, am I doing it right ?
CREATE PROCEDURE P_ValidateTIDIP(in_Tid IN VARCHAR2,in_IP IN VARCHAR2,outstaticip OUT VARCHAR2,outcount OUT NUMBER,outretvalue OUT NUMBER)
AS
BEGIN
select STATIC_IP into outstaticip from OP_TTER_MAPPING where TERMINAL_ID = in_Tid;
if in_IP = outstaticip then
outretvalue:=1;
else
select COUNT(*) into outcount from OP_TTER_MAPPING where DYNAMIC_IP_LOW <= in_IP AND DYNAMIC_IP_HIGH >= in_IP AND TERMINAL_ID = in_Tid;
if outcount = 1 then
outretvalue:=1;
else
outretvalue:=0;
end if;
end if;
END;
In Stored procedure, you return the values using OUT parameter ONLY. As you have defined two variables in your example:
outstaticip OUT VARCHAR2, outcount OUT NUMBER
Just assign the return values to the out parameters i.e. outstaticip and outcount and access them back from calling location. What I mean here is: when you call the stored procedure, you will be passing those two variables as well. After the stored procedure call, the variables will be populated with return values.
If you want to have RETURN value as return from the PL/SQL call, then use FUNCTION. Please note that in case, you would be able to return only one variable as return variable.
Use FUNCTION:
CREATE OR REPLACE FUNCTION test_function
RETURN VARCHAR2 IS
BEGIN
RETURN 'This is being returned from a function';
END test_function;
-- IN arguments : you get them. You can modify them locally but caller won't see it
-- IN OUT arguments: initialized by caller, already have a value, you can modify them and the caller will see it
-- OUT arguments: they're reinitialized by the procedure, the caller will see the final value.
CREATE PROCEDURE f (p IN NUMBER, x IN OUT NUMBER, y OUT NUMBER)
IS
BEGIN
x:=x * p;
y:=4 * p;
END;
/
SET SERVEROUTPUT ON
declare
foo number := 30;
bar number := 0;
begin
f(5,foo,bar);
dbms_output.put_line(foo || ' ' || bar);
end;
/
-- Procedure output can be collected from variables x and y (ans1:= x and ans2:=y) will be: 150 and 20 respectively.
-- Answer borrowed from: https://stackoverflow.com/a/9484228/1661078
It is possible.
When you use Return inside a procedure, the control is transferred to the calling program which calls the procedure. It is like an exit in loops.
It won't return any value.
CREATE PROCEDURE pr_emp(dept_id IN NUMBER,vv_ename out varchar2 )
AS
v_ename emp%rowtype;
CURSOR c_emp IS
SELECT ename
FROM emp where deptno=dept_id;
BEGIN
OPEN c;
loop
FETCH c_emp INTO v_ename;
return v_ename;
vv_ename := v_ename
exit when c_emp%notfound;
end loop;
CLOSE c_emp;
END pr_emp;