I am getting an ORA-00905: missing keyword error when running in the following procedure using the SQLPLUS command line. Strangely it compiles and works when I run it in via an SQL window in PL/SQL developer, unfortunately I need it to work via the command line as well:
CREATE OR REPLACE PROCEDURE PRO_INSERT_ALERT_END_DATE IS
CURSOR cur_InsertEndDate IS
SELECT cli_per_id,
date_ended,
date_started,
alertid
FROM CP_END_ALERT;
BEGIN
FOR rec_cur_InsertEndDate IN cur_InsertEndDate
LOOP
BEGIN
UPDATE vwe_alert_table
SET alert_inactive_on = rec_cur_InsertEndDate.date_ended,
alert_inac_reason = 'Deregistered'
WHERE vwe_alert_table.art_id = rec_cur_InsertEndDate.alertid AND
vwe_alert_table.art_per_id = rec_cur_InsertEndDate.cli_per_id AND
vwe_alert_table.art_alerted_on = rec_cur_InsertEndDate.date_started AND
vwe_alert_table.art_alert = 'AL02';
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error updating record ' || SUBSTR(SQLERRM, 1, 250));
ROLLBACK;
END;
END LOOP;
END PRO_INSERT_ALERT_END_DATE;
Any advice would be most welcome
It is probably due to the blank lines in the script. Tell SqlPlus to ignore them
set sqlblanklines on
Related
I just referred to similar post related to same ORA & PLS error I faced, but still I can't resolve it using provided solution.
I get the following error: PLS-00103: Encountered the symbol “end-of-file” when expecting one of the following: begin function pragma procedure
My code:
create package PACHET is
procedure adaugaAngajat (v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type );
procedure modificaAngajat(v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type );
function verifica_telefon(v_tel angajati.telefon%type)
return boolean;
exp1 exception;
end;
create or replace package body PACHET is
procedure adaugaAngajat (v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type)
is
begin
if ( verifica_telefon(v_tel))
then
raise exp1;
else
insert into angajati values (v_id, v_idL, v_numeP, v_prenume, v_ore, v_sal, v_dat, v_tel, v_post);
end if;
exception
when exp1 then
dbms_output.put_line('Exista deja acest angajat!');
end;
As you tagged the question with Oracle Apex, I presume you're trying to create that package in its SQL Workshop. Of so, it can't execute more than a single statement at a time.
Therefore, put only package specification into the editor and run it. Then delete it and put package body into the editor and run that piece of code.
Alternatively, select (paint it blue) package spec statement and run it; then deselect it and select package body instead to run that statement.
PLS-00103, In short, this error means you have done some syntax error in your pl/SQL code, adding syntax that we should follow
--Firstly creating a declaration of a package
CREATE OR REPLACE PACKAGE PACHET
IS
PROCEDURE EXAMPLE(...);
.
.
END PACHET;
/
I think you have not ended the package and that is causing an error if I am not wrong or you have not pasted your full code, also you can add the name of the procedure or package with the end statements that would make it easy to follow the code.
Also first define the package(specs) and then run the body part.
create or replace package body PACHET is
procedure adaugaAngajat (v_id angajati.id_ang%type, v_idL angajati.id_lab%type, v_numeP angajati.nume%type, v_prenume angajati.prenume%type, v_ore angajati.ore_lucrate%type, v_sal angajati.salariul%type, v_dat angajati.data_angajare%type, v_tel angajati.telefon%type, v_post angajati.postocupat%type)
is
begin
if ( verifica_telefon(v_tel))
then
raise exp1;
else insert into angajati values (v_id, v_idL, v_numeP, v_prenume, v_ore, v_sal, v_dat, v_tel, v_post);
end if;
exception
when exp1 then
dbms_output.put_line('Exista deja acest angajat!');
end adaugaAngajat;
end PACHET;
/
I have the following code:
declare
y pls_integer := 0;
v_msg varchar2(4000);
plsql varchar(4000);
begin
if not apex_collection.collection_exists(p_collection_name=>'P16_COLLECTION') then
wwv_flow.debug('No Apex collection found!');
else
for x in (select * from apex_collections where collection_name = 'P16_COLLECTION' and seq_id > 1 order by seq_id)
loop
y := y+1;
FOR i IN 1..25
LOOP
plsql := 'begin apex_collection.update_member_attribute (p_collection_name=> ''P16_COLLECTION'', p_seq=>' || TO_CHAR(x.seq_id) || ',p_attr_number =>' || TO_CHAR(i) || ',p_attr_value=>wwv_flow.g_f' || TO_CHAR(i, 'FM00') || '(' || TO_CHAR(y) || ')); end;';
wwv_flow.debug(plsql);
EXECUTE IMMEDIATE plsql;
END LOOP;
end loop;
end if;
exception when others then
v_msg := ''||sqlerrm;
wwv_flow.debug('ERR: '||v_msg);
end;
This code is very similar to the one proposed here, but I loop through 25 columns. The issue with Oracle Apex is the max number of chars PL/SQL is allowed to have, so I am unable to just write 25 update_member_attribute - calls.
But instead of a it excecuting I get an error no data found.
I triple checked that the collection P16_COLLECTION exists.
The issue with Oracle Apex is the max number of chars PL/SQL is allowed to have
I'm not sure I understood this statement. It is PL/SQL you use. You declared a local PLSQL variable as VARCHAR2(4000). Why didn't you specify its max allowed size, 32767? Would that help?
Furthermore, saying that you got NO-DATA-FOUND exception: are you sure that this piece of code raised it? Because, there's no SELECT statement in there ... the one you used in a cursor FOR loop can't raise NO-DATA-FOUND; UPDATE either. Therefore, it must be something else, I presume.
Enable DEBUG, run the page and - when you get the error - view debug results and locate the culprit.
My whole intention to catch exception,WRONG parameter is NOT CATCHING exception.
Here is the code:
CREATE OR REPLACE PROCEDURE list_emp (p_emp_id IN employees.employee_id%TYPE,
p_dept_id IN employees.department_id%TYPE)
IS
CURSOR c1 IS
SELECT *
FROM EMPLOYEES
WHERE EMPLOYEE_ID=p_emp_id
AND DEPARTMENT_ID=p_dept_id;
emp_rec c1%ROWTYPE;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO emp_rec;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(emp_rec.employee_id||' '||emp_rec.first_name||' '||emp_rec.last_name);
END LOOP;
CLOSE c1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No Record Found ');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('No Record Found ');
END;
When the cursor is opened and fetched with the wrong parameter that does not match any row from the corresponding table, the following line
EXIT WHEN c1%NOTFOUND;
cause the plsql procedure to terminate (because there were no rows found). Hence no exception is raised.
If you do want to display some sort of output you can do the following instead
IF c1%FOUND THEN
dbms_output.put_line('Record Found');
ELSE
dbms_output.put_line('Finished/Done');
EXIT;
END IF;
If you want to raise an error after looping through a cursor that returns no rows, then you're going to have to use a counter to work out how many rows have been processed, and then you can do something if no rows have been processed.
Something like:
create or replace procedure list_emp (p_emp_id in employees.employee_id%type,
p_dept_id in employees.department_id%type)
is
cursor c1 is
select employee_id,
first_name,
last_name
from employees
where employee_id = p_emp_id
and department_id = p_dept_id;
v_count number := 0;
begin
for emp_rec in c1
loop
v_count := v_count + 1;
dbms_output.put_line(emp_rec.employee_id||' '||emp_rec.first_name||' '||emp_rec.last_name);
end loop;
if v_count = 0 then
raise no_data_found;
end if;
exception
when no_data_found then
dbms_output.put_line('No Record Found.');
raise;
when others then
dbms_output.put_line('An error occurred: '||sqlerrm);
raise;
end;
/
A few notes:
I converted your cursor loop into a cursor-for-loop; you don't need to worry about declaring the record type and also Oracle handles the opening and closing of the cursor for you.
I added raise; to each of your exception handlers - in general, having when others then null (which is effectively what your original code was doing - no errors are raised to the calling code) is a bad idea. I added the raise to the no_data_found condition as that wasn't doing anything either; typically, if you have an exception condition, you want it to do something to let the calling code know there was a problem (not always, of course; sometimes you don't want the processing to stop if a particular error condition is met).
Your cursor was selecting all columns, but in your procedure, you were only using three of them. I've therefore amended the cursor so that it only pulls back those three columns.
Don't rely on dbms_output in your production code. Code that calls this procedure won't see anything populated in dbms_output, unless it explicitly looks for it - and that's not something I've ever seen in any production code, outside of Database tools (eg. SQL*Plus, Toad, etc). I've left this in your procedure as I've a feeling this is a learning exercise for you, but please don't think that this is in any way acceptable in production code.
You're passing p_emp_id in as a parameter - typically, that's the primary key of the employees table. If that's the case, then there's no need for the cursor for loop at all - you could do it by using select ... into ... instead, like so:
.
create or replace procedure list_emp (p_emp_id in employees.employee_id%type,
p_dept_id in employees.department_id%type)
is
v_emp_id employees.employee_id%type;
v_first_name employees.first_name%type;
v_last_name employees.last_name%type;
begin
select employee_id,
first_name,
last_name
into v_emp_id,
v_first_name,
v_last_name
from employees
where employee_id = p_emp_id
and department_id = p_dept_id;
dbms_output.put_line(emp_rec.employee_id||' '||emp_rec.first_name||' '||emp_rec.last_name);
exception
when no_data_found then
dbms_output.put_line('No Record Found.');
raise;
when others then
dbms_output.put_line('An error occurred: '||sqlerrm);
raise;
end;
/
Alternatively, just pass back a ref cursor:
create or replace procedure list_emp (p_emp_id in employees.employee_id%type,
p_dept_id in employees.department_id%type,
p_ref_cur out sys_refcursor)
is
begin
open p_ref_cur for select employee_id,
first_name,
last_name
from employees
where employee_id = p_emp_id
and department_id = p_dept_id;
-- No need for an exception handler here since you're not storing the error details anyway.
-- By not having an error handler, any error will automatically be raised up to the calling code
-- and it will have the correct error stack trace info (e.g. the line number the error occurred,
-- rather than the line the error was reraised from
end;
/
And to run the ref cursor in SQL*Plus (or as a script in Toad/SQL Developer/etc), you do the following:
-- create a variable outside of PL/SQL to hold the ref cursor pointer (this is a SQL*Plus command):
variable rc refcursor;
-- populate our ref cursor variable with the pointer. Note how we pass it in as a bind variable
begin
list_emp(p_emp_id => 1234,
p_dept_id => 10,
p_ref_cur => :rc);
end;
/
-- finally, print the contents of the ref cursor.
print rc;
im new with PL_SQL, i want to ask a question. A need to terminate this script when reaches te exit condition, but its failing, it continues. Im not able to terminate the execution of the script when WHENEVER SQLERROR EXIT SQL.SQLCODE is reached. Any suggestions??
WHILE V_COUNT_MENSAJES>0
LOOP
DELETE
FROM TB_ICP_ENVIOMENSAJES
WHERE KEY_MENSAJE = P_KEY_MENSAJE;
WHENEVER SQLERROR EXIT SQL.SQLCODE;
END LOOP;
END;
WHEN others THEN
dbms_output.put_line('Error en la consulta!');
END;
-----REST OF CODE
Try to incorporate the below snippet it will help to terminate the
code whenever you reach any exception. Hope this helps.
DECLARE
p_err_cd PLS_INTEGER;
p_err_msg VARCHAR2(32767 CHAR);
V_COUNT_MENSAJES PLS_INTEGER;
P_KEY_MENSAJE VARCHAR2(1000 CHAR);
BEGIN
WHILE V_COUNT_MENSAJES > 0
LOOP
BEGIN
DELETE FROM TB_ICP_ENVIOMENSAJES WHERE KEY_MENSAJE = P_KEY_MENSAJE;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,SQLERRM,TRUE);
END;
END LOOP;
END;
You don't have to use "WHENEVER SQLERROR EXIT SQL.SQLCODE;" code inside PLSQL block.Whenever error occur control will pass to exception.Please see the below example for the same.
DECLARE
V_COUNT_MENSAJES NUMBER:=10;
ERROR_1 EXCEPTION;
BEGIN
WHILE V_COUNT_MENSAJES>0
LOOP
RAISE ERROR_1;
END LOOP;
EXCEPTION
WHEN others THEN
dbms_output.put_line('Error en la consulta!');
END;
/
Also please note when you’re executing a script, there are many cases in which you want an error to cause SQL*Plus to terminate where we use the following command and not inside plsql block:
SQL> WHENEVER SQLERROR EXIT SQL.SQLCODE
I create a trigger to check COUNT.
create or replace
TRIGGER TEST_TRG before INSERT OR UPDATE ON TEST
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
AVAILABLE INTEGER;
BEGIN
IF UPDATING THEN
IF(:new.STATUS = 600 OR :new.STATUS = 700) THEN
SELECT COUNT(1) INTO AVAILABLE FROM TEST T WHERE T.IDDISPLAY = :new.IDDISPLAY
AND T.STATUS NOT IN (600,700);
IF(AVAILABLE = 0) THEN
InsertOrUpdateAnotherTable(:new.IDDISPLAY, :new.STATUS, 0);
ELSE
RETURN;
END IF;
END IF;
END IF;
After I change the status to 600 in Test Table, there are errors.
ORA-04091: table USER.TEST is mutating, trigger/function may not see it
ORA-06512: at "USER.TEST_TRG ", line 8
ORA-04088: error during execution of trigger 'USER.TEST_TRG'
I will insert or update another table if the condition is met.
The error is because I try to get COUNT of the current table when the trigger is triggering the same table. This will cause mutating happens.
I have try transaction_anonymous and Compound Trigger, but at the end still same error occurs.
Anyone can help me for another solution, please.
Firstly:
This below line
IF(AVAILABLE = 0) THEN
never will be reached, even if you could eliminate mutating error.
Checking count like this: COUNT(1) INTO AVAILABLE will throw exception "no data found" when there is really no records you're quering.
Secondly:
using compund trigger with section AFTER EACH ROW let you avoid mutating as Tom wrote http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm:
Try this:
create or replace
TRIGGER TEST_TRG FOR INSERT OR UPDATE ON TEST
COMPOUND TRIGGER
AVAILABLE INTEGER;
AFTER EACH ROW IS
BEGIN
IF UPDATING THEN
IF(:new.STATUS = 600 OR :new.STATUS = 700) THEN
BEGIN
SELECT COUNT(1) INTO AVAILABLE FROM TEST T WHERE T.IDDISPLAY = :new.IDDISPLAY
AND T.STATUS NOT IN (600,700);
EXCEPTION
WHEN NO_DATA_FOUND THEN
InsertOrUpdateAnotherTable(:new.IDDISPLAY, :new.STATUS, 0);
END;
END IF;
END IF;
END AFTER EACH ROW;
END TEST_TRG;