Plsql procedure and exception - oracle

Write a PL/SQL procedure: when somebody enters a number, it'll print that number. Otherwise, it'll display error message.

You could also try to convert your input string to a number, and then catch the potential conversion error
Create Or Replace Procedure is_number(p_num varchar2) Is
v_num Number;
Begin
v_num := to_number(p_num);
dbms_output.put_line(v_num);
Exception
When VALUE_ERROR Then
dbms_output.put_line(p_num || ' is not a number');
End is_number;

Not too smart, but will get you started.
Using regular expressions (REGEXP_LIKE), check whether value is a number, consisting of
any number of digits [0-9]+
optionally |
followed by a decimal point . (backslash is here to escape it, as dot represents any character in a regular expression)
followed by any number of digits [0-9]+
^ and $ are anchors for beginning and end of entered value (i.e. it must begin and end with a digit)
Here it is:
SQL> create or replace procedure p_test (par_input in varchar2)
2 is
3 begin
4 if regexp_like(par_input, '^[0-9]+|(\.[0-9]+)$') then
5 dbms_output.put_line(par_input);
6 else
7 dbms_output.put_line('Error');
8 end if;
9 end;
10 /
Procedure created.
SQL> set serveroutput on;
SQL>
SQL> begin
2 p_test('2');
3 p_test('2.13');
4 p_test('x');
5 p_test('&#');
6 end;
7 /
2
2.13
Error
Error
PL/SQL procedure successfully completed.
SQL>

You can do it like this,
set serveroutput on;
BEGIN
DBMS_OUTPUT.PUT_LINE('&number'+0);
EXCEPTION
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('Error');
END;
/

Related

ORA-00900: invalid SQL statement- when run a package in oracle 12c

I am using Oracle 12c database and trying to run a package using SQL commands.
CREATE OR REPLACE PACKAGE "PK_CP_OTM" as
FUNCTION F_CP_OPTIMIZATION (
v_current_day IN VARCHAR2,
v_branch_code IN VARCHAR2)
RETURN VARCHAR2;
END PK_CP_OTM;
When I try to execute it using:
DECLARE
BEGIN
EXECUTE IMMEDIATE PK_CP_OTM.F_CP_OPTIMIZATION('20190409','BRNCD001');
END;
It shows:
ORA-00900: invalid SQL statement
ORA-06512: at line 3
00900. 00000 - "invalid SQL statement"
Thanks for your help.
As #Littlefoot said, you don't need dynamic SQL here, you can make a static call; but as you are calling a function you do need somewhere to put the result of the call:
declare
l_result varchar2(30); -- make it a suitable size
begin
l_result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
end;
/
In SQL*Plus, SQL Developer and SQLcl you can use the execute client command (which might have caused some confusion) and a bind variable for the result:
var result varchar2(30);
exec :result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
print result
There's nothing dynamic here, so - why would you use dynamic SQL at all?
Anyway: if you insist, then you'll have to select the function into something (e.g. a local variable). Here's an example
First, the package:
SQL> set serveroutput on
SQL>
SQL> create or replace package pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2;
6 end pk_cp_otm;
7 /
Package created.
SQL> create or replace package body pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2
6 is
7 begin
8 return 'Littlefoot';
9 end;
10 end pk_cp_otm;
11 /
Package body created.
How to call the function?
SQL> declare
2 l_result varchar2 (20);
3 begin
4 execute immediate
5 'select pk_cp_otm.f_cp_optimization (''1'', ''2'') from dual'
6 into l_result;
7
8 dbms_output.put_line ('result = ' || l_result);
9 end;
10 /
result = Littlefoot
PL/SQL procedure successfully completed.
SQL>

Procedure gives empty result when called

I have created a simple procedure to reverse a number in PL/SQL. The procedure executes fine, but the result doesn't get print. Here's the proc,
CREATE OR REPLACE PROCEDURE SAMPLE_REV (myinput IN NUMBER, finalresult OUT NUMBER)
IS
OperInput NUMBER;
MYREMAINDER NUMBER;
MYRESULT NUMBER;
BEGIN
OperInput:=myinput;
while OperInput!=0 LOOP
MYREMAINDER:=mod(OperInput,10);
MYRESULT:=(MYRESULT*10)+MYREMAINDER;
OperInput:=TRUNC(OperInput/10);
end LOOP;
finalresult:=MYRESULT;
END;
Procedure, when executed works fine. But, when I call on the procedure by the following code,
DECLARE
ENTER NUMBER;
finalresult NUMBER;
BEGIN
ENTER:=&ENTER;
SAMPLE_REV(ENTER,finalresult);
dbms_output.put_line('Output is '|| finalresult);
END;
The result is empty as,
Output is
PL/SQL procedure successfully completed.
I can't come to know the error here, if any. And thanks for the help.
the procedure is using MYRESULT before it is initialized hence null. So this line:
MYRESULT:=(MYRESULT*10)+MYREMAINDER;
is essentially
MYRESULT:=(<<<NULL>>>*10)+MYREMAINDER;
So null overall.
Just adding a :=0 to the declaration will get it working. Also add the set serveroutput on
SQL>set serveroutput on
SQL>CREATE OR REPLACE PROCEDURE SAMPLE_REV (myinput IN NUMBER, finalresult OUT NUMBER)
2 IS
3 OperInput NUMBER;
4 MYREMAINDER NUMBER;
5 MYRESULT NUMBER :=0;
6 BEGIN
7 OperInput:=myinput;
8
9 while OperInput!=0 LOOP
10
11 MYREMAINDER:=mod(OperInput,10);
12 MYRESULT:=(MYRESULT*10)+MYREMAINDER;
13 OperInput:=TRUNC(OperInput/10);
14
15 end LOOP;
16
17 finalresult:=MYRESULT;
18
19 END;
20* /
Procedure SAMPLE_REV compiled
SQL>DECLARE
2 ENTER NUMBER;
3 finalresult NUMBER;
4 BEGIN
5 ENTER:=&ENTER;
6 SAMPLE_REV(ENTER,finalresult);
7 dbms_output.put_line('Output is '|| finalresult);
8 END;
9 /
Enter value for ENTER: 987
Output is 789
PL/SQL procedure successfully completed.
SQL>
In order to view the output of a PL/SQL procedure using dbms_ouput.put_line, run the following command in your session window:
SET SERVEROUTPUT ON;
Should do the trick :)
I see your calculation is not correct. I have added additional output in the procedure to see what it is printing.
MYRESULT itslef is empty and hence you see the output is empty.
set serveroutput on;
CREATE OR REPLACE PROCEDURE SAMPLE_REV (myinput IN NUMBER, finalresult OUT NUMBER)
IS
OperInput NUMBER;
MYREMAINDER NUMBER;
MYRESULT NUMBER;
BEGIN
OperInput:=myinput;
while OperInput!=0 LOOP
MYREMAINDER:=mod(OperInput,10);
dbms_output.put_line('remainder ' || MYREMAINDER);
dbms_output.put_line('in ' || MYRESULT);
MYRESULT:=(MYRESULT*10)+MYREMAINDER;
dbms_output.put_line('out ' || MYRESULT);
OperInput:=TRUNC(OperInput/10);
end LOOP;
finalresult:=MYRESULT;
END;
This line is the problem:
MYRESULT:=(MYRESULT*10)+MYREMAINDER;
On the first iteration MYRESULT is null. So the MYRESULT*10 will be also null. And null + MYREMAINDER = null;
Initialize MYRESULT in the declare section to 0;

sql plus warning in procedure. procedure created with compilation error. (procedure with parameter)

hey i am trying to do a pl sql program with the help of procedure. i want to check if number given by user is even or odd using procedure but i am getting an warning : procedure created with compilation error .
create or replace procedure even( a in out number)
as n number :=&n;
begin
if(n,2)=0 then
dbms_output.put_line('even');
else
dbms_output.put_line('odd');
end if;
end;
/
It is meaningless to compile the procedure each time you get user input.You should rather be doing the following.
Compile the procedure without any substitution variables. The parameter should be just IN and not IN OUT unless you want to modify its value inside the procedure.
CREATE OR replace PROCEDURE Even(n IN NUMBER)
AS
BEGIN
IF MOD(n, 2) = 0 THEN
dbms_output.put_line('even');
ELSE
dbms_output.put_line('odd');
END IF;
END;
/
Then execute this compiled procedure as many times as you like by passing user input.
SQL> SET SERVEROUTPUT ON;
SQL> EXEC even ( &n );
Enter value for n: 5
odd
PL/SQL procedure successfully completed.
SQL> EXEC even ( &n );
Enter value for n: 4
even
PL/SQL procedure successfully completed.
Why don't you use you mod function:
if mod(a,2)=0 then
dbms_output.put_line('even');
else
dbms_output.put_line('odd');
end if;
I think you put "n" instead of "a"
Consider using a function instead; in my opinion, it is a better option for such a task than a procedure.
A natural choice would be a function that returns Boolean:
SQL> create or replace function f_is_even (par_n in number)
2 return boolean
3 is
4 begin
5 return mod(par_n, 2) = 0;
6 end;
7 /
Function created.
You'd then use it in some PL/SQL code as the following example (yes, it looks stupid because it appears that it does exactly what your procedure does, but note - this is just an example; in real life, you'd use it in smarter way):
SQL> begin
2 if f_is_even(6) then
3 dbms_output.put_Line('even');
4 else
5 dbms_output.put_Line('odd');
6 end if;
7 end;
8 /
even
PL/SQL procedure successfully completed.
Drawback of such a function is that you can't use it in SQL (but, as I said, PL/SQL):
SQL> select f_is_even(5) from dual;
select f_is_even(5) from dual
*
ERROR at line 1:
ORA-06552: PL/SQL: Statement ignored
ORA-06553: PLS-382: expression is of wrong type
A possible "workaround" is to create a procedure that doesn't return Boolean but, for example, number (0 for "false" and 1 for "true") or string (N for "false, no" and Y for "true, yes"). For example:
SQL> create or replace function f_is_even_01 (par_n in number)
2 -- returns 1 if number is even; returns 0 if number is odd
3 return number
4 is
5 begin
6 return case when mod(par_n, 2) = 0 then 1
7 else 0
8 end;
9 end;
10 /
Function created.
SQL> select f_is_even_01(5) r1,
2 f_is_even_01(6) r2
3 from dual;
R1 R2
---------- ----------
0 1
There's nothing wrong in using a procedure; I just thought that you might want to hear another opinion.

Assign value to Out parameter PL/SQL Error

I have a stored procedure as follows
procedure Save_FormField(name in varchar2,age in varchar2,returnval out varchar2)
begin
update STATEMENT
if SQL%ROWCOUNT>0 then
returnval :='1';
end;
it throws
ORA-06502: PL/SQL: numeric or value error:
character string buffer too smallORA-06512:
at
returnval :='1';
is it wrong?
Have a look at the following test case :
SQL> CREATE OR REPLACE
2 PROCEDURE Save_FormField(
3 name IN VARCHAR2,
4 RETURNVAL OUT VARCHAR2)
5 AS
6 BEGIN
7 UPDATE EMP1 SET ENAME = 'Hello' WHERE ENAME = name;
8 IF SQL%ROWCOUNT>0 THEN
9 RETURNVAL :='1';
10 END IF;
11 END;
12 /
Procedure created.
SQL>
SQL> declare
2 ret varchar2(100);
3 a varchar2(1);
4 BEGIN
5 Save_FormField('SCOTT',ret);
6 a:= ret;
7 dbms_output.put_line(a);
8 END;
9 /
1
PL/SQL procedure successfully completed.
It definitely looks like that this error is thrown directly in the update statement.
You should check the length of the columns in your table and the length of the values you are trying to update.
Also be carefull with the return value (returnval).
If the update statement doesn't update any record, it is null.
You might want to consider an else-block to set another value in this case.
I know it is a little bit late, but I see there is no answer, so maybe this helps other people.
If you are calling that procedure with using ODP.NET, then you just have to set length of the out parameter.
An example:
cmd.Parameters.Add("returnval", OracleDbType.Varchar2, 500, "", ParameterDirection.Output);
Here 500 is the length of out parameter. Hope, it helps.

How can we define output parameter size in stored procedure?

How can we define output parameter size in stored procedure?
You can't. Of course, you are in control of how much data you put into the OUT parameter in the stored procedure. If you want you can create a sized local variable to hold the data and then assign the value of that variable to the OUT parameter.
The calling program determines the size of the variable that receives the OUT parameter.
Here is a simple package which declares and uses a subtype:
SQL> create or replace package my_pkg as
2 subtype limited_string is varchar2(10);
3 procedure pad_string (p_in_str varchar
4 , p_length number
5 , p_out_str out limited_string);
6 end my_pkg;
7 /
Package created.
SQL> create or replace package body my_pkg as
2 procedure pad_string
3 (p_in_str varchar
4 , p_length number
5 , p_out_str out limited_string)
6 as
7 begin
8 p_out_str := rpad(p_in_str, p_length, 'A');
9 end pad_string;
10 end my_pkg;
11 /
Package body created.
SQL>
However, if we call PAD_STRING() in such a way that the output string exceeds the subtype's precision it still completes successfully. Bother!
SQL> var out_str varchar2(128)
SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
PL/SQL procedure successfully completed.
SQL>
SQL> select length(:out_str) from dual
2 /
LENGTH(:OUT_STR)
----------------
12
SQL>
This is annoying but it's the way PL/SQL works so we have to live with it.
The way to resolve the situaton is basically to apply DBC principles and validate our parameters. So, we can assert business rules against the inputs like this:
SQL> create or replace package body my_pkg as
2 procedure pad_string
3 (p_in_str varchar
4 , p_length number
5 , p_out_str out limited_string)
6 as
7 begin
8 if length(p_in_str) + p_length > 10 then
9 raise_application_error(
10 -20000
11 , 'Returned string cannot be longer than 10 characters!');
12 end if;
13 p_out_str := rpad(p_in_str, p_length, 'A');
14 end pad_string;
15 end my_pkg;
16 /
Package body created.
SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
BEGIN my_pkg.pad_string('PAD THIS!', 12, :out_str); END;
*
ERROR at line 1:
ORA-20000: Returned string cannot be longer than 10 characters!
ORA-06512: at "APC.MY_PKG", line 9
ORA-06512: at line 1
SQL>
Or we can assert business rules against the output like this:
SQL> create or replace package body my_pkg as
2 procedure pad_string
3 (p_in_str varchar
4 , p_length number
5 , p_out_str out limited_string)
6 as
7 l_str limited_string;
8 begin
9 l_str := rpad(p_in_str, p_length, 'A');
10 p_out_str := l_str;
11 end pad_string;
12 end my_pkg;
13 /
Package body created.
SQL>
SQL> exec my_pkg.pad_string('PAD THIS!', 12, :out_str)
BEGIN my_pkg.pad_string('PAD THIS!', 12, :out_str); END;
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "APC.MY_PKG", line 9
ORA-06512: at line 1
SQL>
In most scenarios we should do both. This is the polite way to build interfaces, because it means other routines can call our procedures with the confidence that they will return the values they say they will.
You could use a subtype in a package header and type check that in the body...
CREATE OR REPLACE PACKAGE my_test
AS
SUBTYPE my_out IS VARCHAR2( 10 );
PROCEDURE do_something( pv_variable IN OUT my_out );
END;
/
CREATE OR REPLACE PACKAGE BODY my_test
AS
PROCEDURE do_something( pv_variable IN OUT my_out )
IS
lv_variable my_out;
BEGIN
-- Work on a local copy of the variable in question
lv_variable := 'abcdefghijklmnopqrstuvwxyz';
pv_variable := lv_variable;
END do_something;
END;
/
Then when you run this
DECLARE
lv_variable VARCHAR2(30);
BEGIN
my_test.do_something( lv_variable );
DBMS_OUTPUT.PUT_LINE( '['||lv_variable||']');
END;
/
You would get the error
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
Seems to go against the spirit of using an out parameter, but after Tony's comment this was the only thing I could think of to control data within the called code.

Resources