Encountered the symbol PLSQL - oracle

I'm trying to create a procedure that after finding all the necessary data prints on screen each one of them.
This procedure searches for members, and it receives two parameters, P_CRITERIO if you are looking for a memeber by ID, Last name or national id, and P_SOCIO which has the id, last name or national id.
I tried deleting the Exception part, I didn't get the same error but I still got one that I can't fix
CREATE OR REPLACE PROCEDURE P_CONSULTAR_SOCIOS (P_CRITERIO IN VARCHAR2,P_SOCIO IN VARCHAR2)
IS
V_SENT_SOCIO SOC_SOCIO%rowtype;
V_DEUDA NUMBER;--total dept
V_SALDO NUMBER;--available money
capital_pagado NUMBER;--how much he has paid
capital_a_pagar NUMBER;--how much he has to pay
V_APORTES NUMBER;--total contributions
BEGIN
IF UPPER(P_CRITERIO) = 'ID' THEN
SELECT * INTO V_SENT_SOCIO FROM SOC_SOCIO WHERE ID_SOCIO=P_SOCIO;
ELSE IF UPPER(P_CRITERIO) = 'CEDULA' THEN
SELECT * INTO V_SENT_SOCIO FROM SOC_SOCIO WHERE CEDULA=P_SOCIO;
ELSE IF UPPER(P_CRITERIO) = 'APELLIDO' THEN
SELECT * INTO V_SENT_SOCIO FROM SOC_SOCIO WHERE APELLIDO=P_SOCIO;
END IF;
--available money
SELECT NVL(SALDO_DISPONIBLE,0) INTO V_SALDO
FROM AHO_CUENTA_AHORRO
WHERE ID_SOCIO = V_SENT_SOCIO.ID_SOCIO;
--calculates if he has any loan active and the amount is stored in V_DEUDA
select sum(capital_pagado) into capital_pagado from cre_prestamos where id_sol_cred=V_SENT_SOCIO.ID_SOCIO;
select sum(capital_a_pagar) into capital_a_pagar from cre_prestamos where id_sol_cred=V_SENT_SOCIO.ID_SOCIO and UPPER(estado)='A';
V_DEUDA := (capital_pagado - capital_a_pagar);
--sum of total contributions
select sum(nvl(sdo.monto,0)) into V_APORTES from soc_detalle_obligaciones sdo
join soc_obligaciones o on sdo.id_obligacion = o.id_obligacion
where o.ID_SOCIO=V_SENT_SOCIO.ID_SOCIO and o.tipo_obligacion = 'A';
--prints result
DBMS_OUTPUT.PUT_LINE('| '||V_SENT_SOCIO.ID_SOCIO||' | '||V_SENT_SOCIO.CEDULA||
' | '||V_SENT_SOCIO.NOMBRE_APELLIDO||' | '||' | '||V_SALDO||' | '||V_DEUDA||' | '||
V_APORTES||' |');
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE(-20032,'El socio no existe');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Ha ocurrido un error');
END P_CONSULTAR_SOCIOS;
/
the errors I'm getting says
42/1 PLS-00103: Encountered the symbol "EXCEPTION" when expecting one
of the following:
( begin case declare end exit for goto if loop mod null
pragma raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
47/23 PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
end not pragma final instantiable order overriding static
member constructor map

There are somethings wrong with your code.
To fix the error with the if, you can replace that part of the code with this
IF UPPER(P_CRITERIO) = 'ID' THEN
SELECT * INTO V_SENT_SOCIO FROM SOC_SOCIO WHERE ID_SOCIO=P_SOCIO;
ELSIF UPPER(P_CRITERIO) = 'CEDULA' THEN
SELECT * INTO V_SENT_SOCIO FROM SOC_SOCIO WHERE CEDULA=P_SOCIO;
ELSIF UPPER(P_CRITERIO) = 'APELLIDO' THEN
SELECT * INTO V_SENT_SOCIO FROM SOC_SOCIO WHERE APELLIDO=P_SOCIO;
END IF;
There is a mistake with your Exceptions.
PUT_LINE Can't take more than one parameter
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('El socio no existe');
That's what I can see so far

PLS-00103: Encountered the symbol exception always indicates a syntax error. So it is easy to solve by looking at the code above the given line number - 42 in this case - and comparing it with the syntax given in the Oracle PL/SQL documentation.
The problem in your case is that your code could be valid but it's not. You have written
IF ...
ELSE IF
Now that is valid syntax when the second IF is nested:
IF ...
ELSE IF ... END IF;
END IF;
In this scenario every standalone IF is matched with an END IF. But you are actually trying to implement a switch. So you have only one END IF. In this case you must use ELSIF instead:
IF ...
ELSIF ...
END IF;
There is another syntax error in the EXCEPTION block. DBMS_OUTPUT.PUT_LINE() takes one parameter, a string. To return a message with user-defined number use RAISE_APPLICATION_ERROR() function.
The WHEN OTHERS branch is just bad practice. There are literally thousands of Oracle error messages, many of which might trip up your procedure. To condense all those to one generic message is unhelpful to anybody trying to diagnose why the program failed. Initially that will be you, so help yourself as well as the people who will maintain it after you. Also it is also better to raise exceptions rather than use DBMS_OUTPUT: messages can be ignored or go un-noticed, exceptions must be handled.
EXCEPTION
WHEN NO_DATA_FOUND THEN
raise_application_error(-20032,'El socio no existe');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Ha ocurrido un error');
raise;
END P_CONSULTAR_SOCIOS;

Related

PLS-00103: Encountered the symbol "IS" when expecting one of the following: := . ( # % ; not null range default character

I am facing this error:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/11 PLS-00103: Encountered the symbol "IS" when expecting one of the
following:
:= . ( # % ; not null range default character
My package is:
CREATE OR REPLACE PACKAGE BODY EMP_PK AS
PROCEDURE INSERT_TR(EMPNO EMP_20171250.EMPNO%TYPE,ENAME EMP_20171250.ENAME%TYPE,SAL EMP_20171250.SAL%TYPE) IS
INSERT_ERROR EXCEPTION;
CRUSOR C1 IS INSERT INTO EMP_20171250(EMPNO,ENAME,SAL) VALUES(EMPNO,ENAME,SAL);
BEGIN
IF(C1%FOUND) THEN
DBMS_OUTPUT.PUT_LINE('RECORD INSERTED');
ELSE
RAISE INSERT_ERROR;
END IF;
EXCEPTION
WHEN INSERT_ERROR THEN
DBMS_OUTPUT.PUT_LINE('ERROR WHILE RECORD INSERTION');
END INSERT_TR;
END EMP_PK;
it is not CRUSOR but CURSOR
cursor can't contain INSERT statement; it is a SELECT
you are checking whether cursor returned something, but - you never opened it nor fetched from it so it is pretty much useless
insert_error looks like there was an error while inserting a row, but - you are actually raising it if cursor didn't return anything
Basically, you don't need a cursor at all. Such a procedure would do:
PROCEDURE insert_tr (p_empno emp_20171250.empno%TYPE,
p_ename emp_20171250.ename%TYPE,
p_sal emp_20171250.sal%TYPE)
IS
BEGIN
INSERT INTO emp_20171250 (empno, ename, sal)
VALUES (p_empno, p_ename, p_sal);
END insert_tr;
If insert fails, Oracle will raise an exception anyway so - yes, you can handle it/them if you want.
Also, it is good to distinguish parameter names from column names; for example, precede their names with a p_ (as I did).

Catching multiple exception at once in oracle

Please let me know whether it is possible to catch multiple exception at same time in oracle. Not like 1 user defined and 1 is oracle default .I need to catch multiple user defined exception at same time . Kindly let me know how to do .
Thank you !
Certainly, there is - if I understood the question correctly. It is called WHEN OTHERS. Though, people usually misuse it, especially when they use
exception
when others then
null;
end;
as it successfully hides any errors that might appear. WHEN OTHERS is OK during development process, but might be really bad in production, especially if it doesn't contain raise.
Yes, you can do what you want from "When Others" as indicated by #Littlefoot or bulk processing errors (not covered here). But additionally you can have an OR condition exception name clause on the WHEN . It's not very useful as generally requires more code the 2 separate WHEN condition, but it is valid syntax. The following demonstrates various error definition methods and exception processing.
create table except_demo ( id integer, col1 varchar2(20));
insert into except_demo (id, col1)
select 5,'OK' from dual union all
select 6,'Too Many' from dual union all
select 6,'Still' from dual;
select id, count(*) from except_demo group by id;
create or replace procedure catcher(which_in integer, select_in boolean default False)
is
e_user_1 exception;
e_user_2 exception;
invalid_which_range exception;
appErr_inactive_acct exception;
sample_ora_error exception;
pragma exception_init (sample_ora_error, -00060);
rae exception;
rae_num constant integer := -20100;
pragma exception_init (rae, -20100);
col1_value except_demo.col1%type;
begin
dbms_output.put( 'Enter catcher(' || which_in || ') Result=>');
if which_in > 8
then raise invalid_which_range;
end if ;
if select_in
then
select col1
into col1_value
from except_demo
where id = which_in;
dbms_output.put_line('Select Successful 1 row selected.');
else
case which_in
when 1 then raise e_user_1;
when 2 then raise e_user_2;
when 3 then raise appErr_inactive_acct;
when 4 then raise sample_ora_error;
else raise_application_error(rae_num, 'Which_In=' || which_in || ' invalid. Please specify number 1-7 only');
end case;
end if;
exception
when e_user_1
then dbms_output.put_line('Error e_user_1'); -- user error
when e_user_2
then dbms_output.put_line('Error e_user_2');
when no_data_found or too_many_rows
then dbms_output.put_line('Select except_demo where id=' || which_in ||'; Returned 0 or more than 1 row. Must return exactly 1.' ); -- oracle predefined error
when sample_ora_error
then dbms_output.put_line('Ora Error:: ' || sqlerrm ); -- oracle error NOT predefined
when appErr_inactive_acct
then dbms_output.put_line('Error Account id ' || which_in || ' is inactive.'); -- user error
when rae
then dbms_output.put_line(sqlerrm);
end catcher;
declare
do_select boolean;
begin
for i in 1..9
loop
do_select := (i between 5 and 7);
catcher(i,do_select);
end loop;
exception
when others
then
dbms_output.put_line('Error returned from catcher=>' || sqlerrm);
raise;
end ;
drop procedure catcher;
drop table except_demo;
In a live environment the dbms_output statement would be replaced writing the message and other information to a exception log table and NOT dbms_output.
I have a very minor disagreement with Littlefoot. I firmly believe that what ever is written in development, whether intended or not, will run in production. Too often it is the unintended that gets you into trouble. Therefore the example of a misused WHEN OTHERS is invalid even in development.

Which command raised the exception?

Is there a variable like SQLERRM or SQLCODE that holds the statement which raised the error?
example:
/*
if some error raised from this code
and I want to know which statement cause the failure..
I wish to use some oracle varaible to know it
*/
begin
select * from t1;
select * from t2;
exception when others
dbms_output.put_line(sqlerrm || ' raised from this statement:' || <some_variable>;
end;
-- excepted result: no data found raised from this statement: select * from t2
Simple answer, no. You're losing some information by defining an exception handler. With an unhandled exception you'd get an error message which includes the line number. But obviously we need to handle errors, log them, etc. So not having a line number is pretty rubbish.
Fortunately there are a couple of options. In older versions of Oracle we can use dbms_utility.format_error_backtrace() and dbms_utility.format_error_stack() to get some useful information, including the line numbers. It's pretty unwieldy and (especially for the backtrace) verbose.
In Oracle 12c we got a whole package devoted to PL/SQL call stack: UTL_CALL_STACK. It is a box of bits and requires more than one call to get things but we can retrieve a specific line number with unit_line(). Tim Hall has written a typically fine introduction to the new feature. Find out more.
The other thing to consider is how good program design can resolve this problem. Specifically the Single Responsibility Principle. This is a fundamental guideline of program design: a program unit should do one thing. If we asking the question "which command through this error" it can be a sign that we're violating the SRP.
Let's resign your code so it follows this design principle:
declare
type nt1 is table of t1%rowtype;
type nt2 is table of t2%rowtype;
l_t1 nt1;
l_t2 nt2;
x_t1_ndf exception;
x_t2_ndf exception;
function get_t1 return nt1 is
return_value nt1;
begin
select *
bulk collect into return_value
from t1;
if return_value.count() = 0 then
raise x_t1_ndf;
end if;
return return_value;
end get_t1;
function get_t2 return nt2 is
return_value nt2;
begin
select *
bulk collect into return_value
from t2;
if return_value.count() = 0 then
raise x_t2_ndf;
end if;
return return_value;
end get_t2;
begin
l_t1 := get_t1;
l_t2 := get_t2;
exception
when x_t1_ndf then
dbms_output.put_line('T1 has no data');
when x_t2_ndf then
dbms_output.put_line('T2 has no data');
end;
Obviously more typing than your original code but partly that's because this toy is complete working code, unlike the code you posted. Also in real life these modules would be discrete units, rather than private functions in an anonymous block, and so we could re-use them in multiple other programs.
Also dbms_output.put_line() is not the proper way to handle exceptions, but I've left that because it's what your code does.
There is no built-in that you can use for that.
One way could be by handling the exceptions of the single statements, with something like (pseudo-code):
declare
err varchar2(100);
myException exception;
begin
...
begin
select * from t1;
exception
when others then
err := 'Error in select * from t1: ' || sqlerrm;
raise myException
end;
begin
select * from t2;
exception
when others then
err := 'Error in select * from t2: ' || sqlerrm;
raise myException
end;
...
exception
when myException then
dbms_output.put_line(err);
when others then
dbms_output.put_line('Unhandled exception: ' || sqlerrm);
end;
For something more, this can be very useful.
Using a single exception handler for multiple statements always mask
the statement that caused an error.
Instead, you can use a Local variable(Locator) to track statement execution, as follows:
DECLARE
err_stmt NUMBER:= 1; -- Indicates 1st SELECT statement
BEGIN
SELECT ... -- Statement 1
err_stmt := 2; -- Indicates 2nd SELECT statement
SELECT ... -- Statement 2
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(sqlerrm || ' raised from this statement number:' || err_stmt;
END;
Cheers!!

ORA-01722: invalid number Error - 1

I'm stuck and can't see what the problem is.
I created a procedure with some logic stuff and it compiled successfully, but when I call it in a trigger on my table, it fails with ORA-01722: invalid number.
Any help would be gratefully received.
Here is the procedure:
create or replace Procedure Check_Plants_Fields(
field_id IN number ,
farmer_name IN varchar2,
planting_date IN date DEFAULT sysdate,
planting_amount IN number,
plant_type IN number)
IS
l_plant_type XXLA_PLANTS_TYPE.PLANT_TYPE%type;
l_number_of_months XXLA_PLANTS_SUPPLIERS.NUMBER_MONTHS_TO_CUT%type;
cursor c1 is
SELECT PLANT_TYPE , AMOUNT_
FROM XXLA_PLANTS_TYPE
WHERE PLANT_ID = plant_type;
cursor c2 is
SELECT to_number(MOD(Round(DBMS_RANDOM.Value(1, 8)), 9) + 1)
FROM DUAL;
BEGIN
open c1;
open c2;
fetch c2 into l_number_of_months;
if c1 %notfound then
close c1;
dbms_output.put_line('You dont have this type, please supply it to your store . ' || ' ' || 'thanx.');
end if;
for i in (SELECT PLANT_TYPE , AMOUNT_
FROM XXLA_PLANTS_TYPE
WHERE PLANT_ID = plant_type)
LOOP
if i.AMOUNT_ < 20 then
dbms_output.put_line(i.AMOUNT_ ||' AMOUNT_: '|| i.AMOUNT_);
UPDATE XXLA_PLANTS_SUPPLIERS
SET supplier_id = supplier_id_seq.nextval;
INSERT INTO XXLA_PLANTS_SUPPLIERS
(supplier_id, supplier_name, number_months_to_cut, date_,amount, price_in_KG)
VALUES (supplier_id_seq.nextval, 'Benefits etc',l_number_of_months ,sysdate+1, 80 + i.AMOUNT_,'500$');
end if;
END LOOP i;
commit;
close c2;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered,- '||SQLCODE||' -ERROR- -->'||SQLERRM );
END;
And here is the trigger:
create or replace TRIGGER xxbefor_insert_plants
BEFORE INSERT ON XXLA_PLANT_FIELDS
FOR EACH ROW
BEGIN
Check_Plants_Fields(:NEW.field_id, :NEW.farmer_name, :NEW.planting_date, :NEW.planting_amount, :NEW.plant_type);
END;
Here is the insert that executes the trigger that calls the procedure, but it errors when I run it.
INSERT INTO XXLA_PLANT_FIELDS
(field_id, FARMER_NAME,planting_date,planting_amount,plant_type )
VALUES
(4, 'Test1',sysdate,8,1 (because this parameter it should work its under 20 ));
ORA-01722: invalid number is quite a simple error to understand. It means you are attempting to cast a string to a number datatype but the operation fails because the string contains non-numeric characters.
So what this means is that somewhere in your procedure you have a implicit type conversion. You haven't provided the description of the tables so we can't tell you where the problem happens. You'll have to discover it for yourself.
Two places where it might be:
WHERE PLANT_ID = plant_type if XXLA_PLANTS_TYPE.PLANT_ID is not
numeric
VALUES (... '500$'); if
XXLA_PLANTS_SUPPLIERS.PRICE_IN_KG is not numeric
Incidentally, if you removed that pointless exception handler you would get the default error stack. That would tell you the starting line number of the failing statement, which would really remove a lot of the guesswork from the exercise.

How do I handle the exception in this pl/sql for loop correctly?

First off, I'm a relative newbie to PL/SQL so I might be missing something trivial.
Here is a snippet of code that I'm having issues with running -
FOR indx IN 1 .. arr.COUNT
LOOP
SELECT COUNT(*), ca.cities
INTO tmp_count, affected_cities
FROM PDB.utilities ca
WHERE (ca.app_city_id = cityid
AND ca.app_plumbing_id = arr(indx))
AND( BITAND(options1,2) = 2
OR BITAND(options1,1) = 1)
GROUP BY ca.cities;
IF tmp_count >=0 THEN
-- We have an affected app so collect metrics
IF plumbings(indx_mv) ='0Ci30000000GsBN' THEN
count_wrigley:= count_wrigley+tmp_count;
END IF;
counter:= counter+tmp_count; --overall count.
tmp_count:=0;
affected_cities:=null;
END IF;
EXCEPTION -- error thrown here !
WHEN NO_DATA_FOUND THEN
CONTINUE;
END;
END LOOP; -- Error thrown here too.
And here is my error trace -
Error report:
ORA-06550: line 64, column 13:
PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following:
( begin case declare end exit for goto if loop mod null
pragma raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
ORA-06550: line 68, column 11:
PLS-00103: Encountered the symbol "LOOP" when expecting one of the following:
;
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
It's worth noting that the block fails only with the exception handling and compiles successfully otherwise. So my guess is I'm doing something wrong there?
Any help would be greatly appreciated! Thanks
EXCEPTION aligns with BEGIN ... END blocks. There is no BEGIN inside your loop, so there should be no exception either.
It seems the purpose of the exception is to suppress NO_DATA_FOUND errors inside the loop. So to fix this error you need to put a BEGIN / END block in the loop too. (Ah, you have an END just no BEGIN - your code would hurl with the EXCEPTION block).
FOR indx IN 1 .. arr.COUNT
LOOP
BEGIN
SELECT COUNT(*), ca.cities
INTO tmp_count, affected_cities
FROM PDB.utilities ca
....
EXCEPTION
WHEN NO_DATA_FOUND THEN
CONTINUE;
END;
END LOOP;

Resources