Cursor in PL/SQL, my procedure doesnt work - oracle

i have a problem in my procedure...in this case i want to raisy the salary to employees(Empleado) that have been working 5 years or more inn the store "Bodega"(...sorry about my english,i speak spanish XD).
First, i was thinking about select the ID's of all the employees that satisfy the condition (in a cursor) and then compare them to the ID'S in the EMPLEADO TABLE, if the same(the ID'S) then UPDATE the salary...it doesn't work with the IF - END IF (i put in COMMENTS) but without it.
needing help...i am doing something wrong but dont know what it is.
CREATE OR REPLACE PROCEDURE aumento_empleado(idBodega IN CHAR)IS
CURSOR c_empl IS SELECT E.idEmpleado
FROM Empleado E, Bodega B
WHERE( MONTHS_BETWEEN(sysdate,E.fecha_contrato)>=5*12
AND E.id_Bodega=B.id_Bodega
AND B.id_Bodega=idBodega);
idEmpl Char(8);
NO_EMP EXCEPTION;
BEGIN
OPEN c_empl;
LOOP
FETCH c_empl INTO idEmpl;
EXIT WHEN c_empl%notfound;
IF c_empl%ROWCOUNT=0 THEN
RAISE NO_EMP;
END IF;
--IF (idEmpl=Empleado.idEmpleado) THEN
UPDATE Empleado
SET Empleado.Sueldo=Empleado.Sueldo + Empleado.Sueldo*0.05;
--END IF;
END LOOP;
CLOSE c_empl;
EXCEPTION
WHEN NO_EMP THEN
dbms_output.put_line('No hay empleados que cumplan con las condiciones pedidas para la bonificacion' ) ;
WHEN OTHERS THEN
dbms_output.put_line('Error: hubo un error durante la ejecucion del procedimiento' ) ;
END aumento_empleado;

This single statement should work for your purpose
UPDATE Empleado E
SET E.Sueldo=E.Sueldo + E.Sueldo*0.05
WHERE MONTHS_BETWEEN(sysdate,E.fecha_contrato)>=5*12
AND E.id_Bodega IN (SELECT B.id_Bodega FROM Bodega B)
Avoid using loops where they are not absolutely required.

Related

PLS-00049: bad bind variable 'X_VARIABLE'

I'm getting the following error when I trying to get a record from a table, in this case, is (SERVICIOENDIAS)/SERVICETIMEINDAYS and I don't know why I'm getting that errr :
Trigger TRG_CONTROL_SERVICIO compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
20/11 PLS-00049: bad bind variable 'NEW.V_SERVICIODIAS'
Errors: check compiler log
I'm a dummy with Oracle and possibly I may do a lot of mistakes and bad practices, so I'll appreciate it if you can say me that.
CREATE OR REPLACE TRIGGER TRG_CONTROL_SERVICIO
BEFORE
INSERT OR UPDATE
ON SERVICIO
FOR EACH ROW
DECLARE
V_SERVICIODIAS INT;
CURSOR C_SERVICIODIAS IS
SELECT TIEMPOSERVICIODIAS INTO V_SERVICIODIAS
FROM SERVICIO;
BEGIN
FOR R_SERVICIODIAS IN C_SERVICIODIAS LOOP
IF INSERTING THEN
IF :NEW.FECHAREGISTRO > SYSDATE THEN
LOG_AUDIT( USER,
SYSDATE,
'SERVICIO',
'INSERT FECHA INCORRECTA',
'SE EJECUTO EL TRG_CONTROL_SERVICIO');
RAISE_APPLICATION_ERROR(-20000, 'FECHA INCORRECTA, INTENTE DE NUEVO');
ELSE
DBMS_OUTPUT.PUT_LINE('INSERTANDO UN SERVICIO');
END IF;
IF :NEW.V_SERVICIODIAS <= 60 THEN
DBMS_OUTPUT.PUT_LINE('INSERTANDO UN SERVICIO');
ELSE
LOG_AUDIT( USER,
SYSDATE,
'SERVICIO',
'NO SE PUEDE UN SERVICIO MAYOR A 60 DIAS',
'SE EJECUTO EL TRG_CONTROL_SERVICIO');
RAISE_APPLICATION_ERROR(-20000, 'NO SE PUEDE REGISTRAR EL SERVICIO, MUCHAS HORAS',TRUE);
END IF;
ELSIF UPDATING THEN
IF :NEW.FECHAREGISTRO <> :OLD.FECHAREGISTRO AND :NEW.FECHAREGISTRO > SYSDATE THEN
LOG_AUDIT( USER,
SYSDATE,
'SERVICIO',
'PROHIBIDO UPDATE FECHAREGISTRO',
'SE EJECUTO EL TRG_CONTROL_SERVICIO');
RAISE_APPLICATION_ERROR(-20000, 'FECHA INCORRECTA, NO SE PUEDE MODIFICAR ESTA FECHA',TRUE);
ELSE
DBMS_OUTPUT.PUT_LINE('ACTUALIZANDO UN EMPLEADO');
END IF;
END IF;
END LOOP;
END;
In your program V_SERVICIODIAS INT; is a declared variable, so you have to use it syntactically as a variable.
The correct if statement is the following, please try to use it:
IF V_SERVICIODIAS <= 60 THEN
As has been pointed out, V_SERVICIODIAS is a local variable so it's not part of the :NEW pseudorecord. You'd use
IF V_SERVICIODIAS <= 60 THEN
Once you do that, the next issue is that nothing is actually populating that local variable so the if statement can never be true. That's because there is a syntax error in your cursor definition. You use an into clause if you have a select statement that returns a single row not when you're defining a cursor that you plan on looping over
CURSOR C_SERVICIODIAS IS
SELECT TIEMPOSERVICIODIAS
FROM SERVICIO;
Once you fix the cursor definition error, you'd get rid of the local variable entirely and just reference the column from the cursor.
IF R_SERVICIODIAS.TIEMPOSERVICIODIAS <= 60 THEN
Having done all that, however, you're going to encounter a mutating table runtime error because a row-level cursor on the SERVICIO isn't going to be able to query the SERVICIO table. And, unfortunately, at that point it's not obvious how to resolve the problem because it's not obvious why the cursor exists in the first place. Why would you want to loop over every row in the table every time you insert a new row into the table? That doesn't really make any sense.
One possibility is that you don't actually want to loop over every row in the table. Perhaps you want to remove the V_SERVICIODIAS local variable and the cursor definition and the loop and just reference the TIEMPOSERVICIODIAS from the current row.
IF :NEW.TIEMPOSERVICIODIAS <= 60 THEN

when updating a table says im changing values inside the trigger when im not

This trigger is supposed to stop if a interval between two dates are overlaping.
When i try to update a table i get this error where says its in mutation i can't read it or modify, but i don't understand where.
image of the error
The code is:
CREATE OR REPLACE TRIGGER trgepocasnaosobrepostas BEFORE
UPDATE OR INSERT ON epoca
FOR EACH ROW
DECLARE
CURSOR c IS
SELECT
*
FROM
epoca;
cr_epoca c%rowtype;
ex_data_sobreposta EXCEPTION;
ex_data_null EXCEPTION;
BEGIN
OPEN c;
IF inserting THEN
IF ( :new.data_fim IS NULL ) THEN
RAISE ex_data_null;
END IF;
FETCH c INTO cr_epoca;
IF ( ( :new.data_ini BETWEEN cr_epoca.data_ini AND cr_epoca.data_fim ) OR ( :new.data_fim BETWEEN cr_epoca.data_ini AND cr_epoca
.data_fim ) ) THEN
RAISE ex_data_sobreposta;
END IF;
END IF;
CLOSE c;
IF updating THEN
IF ( ( :new.data_ini BETWEEN :old.data_ini AND :old.data_fim ) OR ( :new.data_fim BETWEEN :old.data_ini AND :old.data_fim
) ) THEN
RAISE ex_data_sobreposta;
END IF;
END IF;
EXCEPTION
WHEN ex_data_sobreposta THEN
raise_application_error(-20000, 'datas sobrepõem épocas');
WHEN ex_data_null THEN
raise_application_error(-20000, 'data fim não pode ser null');
END trgepocasnaosobrepostas;
/
Your trigger is defined on the table epoca, and you're attempting to fetch from a cursor on the table epoca inside it. That's not allowed. Complex logic such as this doesn't belong in a trigger. I suggest you write a procedure to perform the updates and all this validation logic.

Update with "with data as" clause and regex do not commit. Why?

Sorry for the delay! I've taken a workload greater then i can handle these couple weeks.
Ok, lets clarify things up!
There is a proprietary software running on top of it and
I do not have de ability to change this software! Actually it allows me to do a few things.
In this specific case I can not create a relation 1>N, I can not create a new table! What I do can is create fields.
So, how do i customize things? Through the database! Using triggers, functions and procedures. I know its a bad "work around" but it's what i got and works flawlessly 99% of times. Any exception my code throws the application shows on the screen!
The problem is actually the update not working.
You ask:
Why you're looping when you're forcing there to only be one iteration (unless P_QTDLINHAS can be < 1 I suppose?)
R: Couse the user can select multiple lines in the application but I dont want them to do it. So a throw an error on the screen.
Why you have nested begin/end blocks.
R: Couse I may have to throw exceptions, I got used to write begin Statements Exception some message end.
Sample data:
CREATE TABLE SAMPLE_DATA
(
PKNUMBER NUMBER NOT NULL
, DESCRIPTION VARCHAR2(20)
, GROUPTOCHANGE VARCHAR2(100)
, STATUS VARCHAR2(1 BYTE)
, CONSTRAINT SAMPLE_DATA_PK PRIMARY KEY
(
PKNUMBER
)
ENABLE
);
INSERT INTO sample_data VALUES (1000,'ORDER1',NULL,NULL);
INSERT INTO sample_data VALUES (2000,'ORDER2',NULL,NULL);
INSERT INTO sample_data VALUES (3000,'ORDER3',NULL,NULL);
INSERT INTO sample_data VALUES (4000,'ORDER4','1000,2000,30001',NULL);
In this case the field GROUPTOCHANGE will be filled by the user like this "2108,8090,8843". Each number represents a PKNUMBER in same table "SAMPLE_DATA".
yes i know! the user can type something wrong.. let's ignore this for now!
The field STATUS will eventually be updated to 'C','L','R' OR NULL. When this happens I Need this logic to be executed:
IF OLD.STATUS <> NEW.STATUS AND GROUPTOCHANGE IS NOT NULL THEN
UPDATE SAMPLE_DATA SP
SET SP.STATUS = :NEW.STATUS
WHERE SP.PKNUMBER IN (:NEW.GROUPTOCHAGE)
AND PS.GROUPTOCHANGE IS NULL;
END IF;
Dispite the bad design is it possible to do?
Thank for any help!!
Here what I've done so far:
create or replace PROCEDURE "AD_LIBERA_FRETES_FILHOS"(
P_CODUSU NUMBER,
P_IDSESSAO VARCHAR2,
P_QTDLINHAS NUMBER,
P_MENSAGEM OUT VARCHAR2)
AS
P_NUNOTA NUMBER(10);
P_CONTROLE VARCHAR(100);
P_PEDIDOS VARCHAR(100);
P_STATUS VARCHAR(100);
BEGIN
-- avoid more than 1 at a time
IF (P_QTDLINHAS > 1) THEN
RAISE_APPLICATION_ERROR(-20000, 'SELECIONE APENAS UM PEDIDO PARA EXECUTAR ESTA AÇÃO.');
END IF;
FOR I IN 1..P_QTDLINHAS LOOP
--extract param from session
P_NUNOTA := ACT_INT_FIELD(P_IDSESSAO, I, 'PKNUMBER');
P_STATUS := ACT_TXT_FIELD(P_IDSESSAO, I, 'STATUS');
--verify typed text should be "84090,89830,83393..."
BEGIN
SELECT REGEXP_REPLACE(CAB.GROUPTOCHANGE, '[0-9-, ]', ''),
CAB.GROUPTOCHANGE
INTO P_CONTROLE,
P_PEDIDOS
FROM SAMPLE_DATA CAB
WHERE CAB.PKNUMBER = P_NUNOTA;
END;
IF (P_CONTROLE IS NOT NULL) THEN
RAISE_APPLICATION_ERROR(-20000, '<B> SOMETHING WRONG !</B>');
ELSE
--perform de update (not working)
BEGIN
UPDATE SAMPLE_DATA C
SET C.STATUS = P_STATUS
WHERE
C.GROUPTOCHANGE IS NULL AND
C.PKNUMBER IN
(WITH DATA AS
(SELECT CAB.GROUPTOCHANGE STR
FROM SAMPLE_DATA CAB
WHERE CAB.PKNUMBER = P_NUNOTA )
SELECT TRIM(REGEXP_SUBSTR(STR, '[^,]+', 1, LEVEL)) STR
FROM DATA CONNECT BY INSTR(STR, ',', 1, LEVEL - 1) > 0);
END;
END IF;
END LOOP;
--mgs to show
P_MENSAGEM := 'DONE!! CHECK -> '||P_PEDIDOS;
END;

PL SQL procedure don't work (probably cursor fault)

I'm starting with PL/SQL, this is my first Procedure and i've trouble to make it work.
i've problem (think) with cursor. If you look my code are four comments; i've tested these four Update, but only one work! and i'm sure that two SELECT work, because if i send wrong parameter in input the select don't give a result.
of the four comments, I want that works:
UPDATE partecipa
SET punti= somma
WHERE ( (nomesquadra= nomesquadr) AND
(nometorneo= nometorn));
If there are other errors (also logical) please tell me. I would like to improve.
Thank you all for the answers
my procedure:
create or replace PROCEDURE calcola_giorn (giornata IN INTEGER) IS
-- si tenga presente che in realtà giornata=idPartita
somma NUMBER;
idcal NUMBER;
nometorn VARCHAR2(100);
idformaz NUMBER;
nomesquadr VARCHAR2(100);
CURSOR formazioni_di_giornata IS
SELECT id, nomesquadra FROM formazione where idpartita= giornata;
CURSOR giocatori_di_giornata IS
SELECT votogiocatore FROM schiera WHERE idformazione= idformaz;
Begin
SELECT idcalendario
INTO idcal
FROM partita
WHERE id= giornata;
SELECT nometorneo
INTO nometorn
FROM calendario
WHERE id= idcal;
FOR tupla_formazione IN formazioni_di_giornata LOOP
somma:=0;
FETCH formazioni_di_giornata INTO idformaz, nomesquadr;
FOR tupla_giocatore IN giocatori_di_giornata LOOP
somma:= somma + tupla_giocatore.votogiocatore;
/*DON'T WORK*/-- UPDATE partecipa SET punti= 123;
END LOOP;
/*WORK*/-- UPDATE partecipa SET punti= 12;
/*DON'T WORK*/-- UPDATE partecipa SET punti= 123 WHERE ( (nomesquadra= nomesquadr) AND (nometorneo= nometorn));
/*DON'T WORK*/-- UPDATE partecipa SET punti= somma WHERE ( (nomesquadra= nomesquadr) AND (nometorneo= nometorn));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'An error was encountered - ' ||
SQLCODE||' -ERROR- '||SQLERRM);
END;
I recommend you rewrite your procedure:
create or replace PROCEDURE calcola_giorn (giornata IN INTEGER) IS
-- si tenga presente che in realtà giornata=idPartita
somma NUMBER;
nometorn VARCHAR2(100);
nOuter_cursor_rows_fetched NUMBER := 0;
Begin
SELECT c.NOMETORNEO
INTO nometorn
FROM PARTITA p
INNER JOIN CALENDARIO c
ON c.ID = p.IDCALENDARIO
WHERE p.ID = giornata;
FOR tupla_formazione IN (SELECT id, nomesquadra
FROM formazione
where idpartita = giornata)
LOOP
DBMS_OUTPUT.PUT_LINE('Inside outer loop, FORMAZIONE.ID=' ||
tupla_formazione.ID);
nOuter_cursor_rows_fetched := nOuter_cursor_rows_fetched + 1;
somma := 0;
FOR tupla_giocatore IN (SELECT votogiocatore
FROM schiera
WHERE idformazione = tupla_formazione.nomesquadra)
LOOP
somma := somma + tupla_giocatore.votogiocatore;
-- The following statement will set PUNTI to 123 on every row in
-- PARTECIPA - are you sure this is what you wanted to do?
UPDATE partecipa SET punti= 123;
END LOOP;
-- The following statement will set PUNTI to 12 on every row in
-- PARTECIPA - are you sure this is what you wanted to do?
UPDATE partecipa SET punti= 12;
UPDATE partecipa
SET punti = 123
WHERE nomesquadra= tuplafomazione.nomesquadra AND
nometorneo = nometorn;
UPDATE partecipa
SET punti = somma
WHERE nomesquadra = tupla_formazione.nomesquadr AND
nometorneo = nometorn;
END LOOP;
DBMS_OUTPUT.PUT_LINE('# rows fetched by outer cursor=' ||
nOuter_cursor_rows_fetched);
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Error: SQLCODE=' ||
SQLCODE||' SQLERRM='''||SQLERRM || '''');
ROLLBACK;
RAISE;
END calcola_giorn;
I believe that #Allan must be right and that the outer loop (for tupla_formazione) is never being entered. The DBMS_OUTPUT.PUT_LINE at the top of this loop is there to demonstrate this. If you don't see any of these lines printed you might need to consider looking at the values which are input to the procedure.
Share and enjoy.
A for loop that invokes a cursor automatically fetches the row once for each loop. The fetch you added inside the loop isn't allowed.
The fact that you're not seeing an ORA-01001: invalid cursor error indicates that you're never getting to the interior of the loop: the formazioni_di_giornata cursor must not be returning any rows.
As an aside, I'd strongly suggest getting rid of the exception clause you're using. All it's doing is adding garbage to the error message.

internal error [phdite:node kind] / looping chain of synonyms

I am getting these errors when executing my code, can anyone give me a solution please?
create or replace procedure old_candidate (ID_M1 candidate.ID_M1%type,ID_M2 candidate.ID_M2%type,ID_M3 candidate.ID_M3%type,ID_M4 candidate.ID_M4%type,nombre_masterss candidate.nombre_masters%type,Lname candidate.Lname%type,Fname candidate.Fname%type,Fname_father candidate.Fname_father%type,mother candidate.mother%type,sex candidate.sex%type,DOB candidate.DOB%type,POB candidate.POB%type,Nat candidate.Nat%type,ncivil candidate.ncivil%type,Cir candidate.Cir%type,building candidate.building%type,street candidate.street%type,region candidate.region%type,nhood candidate.nhood%type,tel_m candidate.tel_m%type,tel_f candidate.tel_f%type,email candidate.email%type,Hschool candidate.Hschool%type,description candidate.description%type,diploma1 candidate.diploma1%type,desc_d1 candidate.desc_d1%type,Diploma2 candidate.Diploma2%type,desc_d2 candidate.desc_d2%type,Diploma3 candidate.Diploma3%type,desc_d3 candidate.desc_d3%type,motivation_m1 candidate.motivation_m1%type,motivation_m2 candidate.motivation_m2%type,motivation_m3 candidate.motivation_m3%type,motivation_m4 candidate.motivation_m4%type)
is
IDs students.ID%type;
pre master.prerequis%type;
test number;
begin
select ID
into IDs
from students
where ID_u=get_current_user_ID;
if nombre_masterss>0 then
select prerequis
into pre
from master
where ID_master=ID_m1;
if pre>0 then select count(*)
into test
from inscriptions
where master_ID=pre and succeeded='Y';
if test=0 then
raise_application_error(-20018,'vous ne pouvez pas s''inscrire au master1 avant de reussir son prerequis');
end if;
end if;
end if;
if nombre_masterss>1 then
select prerequis
into pre
from master
where ID_master=ID_m2;
if pre>0 then select count(*)
into test
from inscriptions
where master_ID=pre and succeeded='Y';
if test=0 then
raise_application_error(-20018,'vous ne pouvez pas s''inscrire au master2 avant de reussir son prerequis');
end if;
end if;
end if;
if nombre_masterss>2 then
select prerequis
into pre
from master
where ID_master=ID_m3;
if pre>0 then select count(*)
into test
from inscriptions
where master_ID=pre and succeeded='Y';
if test=0 then
raise_application_error(-20018,'vous ne pouvez pas s''inscrire au master3 avant de reussir son prerequis');
end if;
end if;
end if;
if nombre_masterss>3 then
select prerequis
into pre
from master
where ID_master=ID_m4;
if pre>0 then select count(*)
into test
from inscriptions
where master_ID=pre and succeeded='Y';
if test=0 then
raise_application_error(-20018,'vous ne pouvez pas s''inscrire au master4 avant de reussir son prerequis');
end if;
end if;
end if;
insert into candidate (ID_c,year,old_new,ID,ID_M1,ID_M2,ID_M3,ID_M4,nombre_masters,etat1,etat2,etat3,etat4,date_candidature,Lname,Fname,Fname_father,mother,sex,DOB,POB,Nat,ncivil,cir,building,street,region,nhood,tel_m,tel_f,email,Hschool,description,diploma1,desc_d1,diploma2,desc_d2,diploma3,desc_d3,motivation_m1,motivation_m2,motivation_m3,motivation_m4)
values(ID_C_seq.nextval,get_annee_scolaire,IDs,'O',ID_M1,ID_M2,ID_M3,ID_M4,nombre_masterss,'P','P','P','P',sysdate,Lname,Fname,Fname_father,mother,sex,DOB,POB,Nat,ncivil,cir,building,street,region,nhood,tel_m,tel_f,email,Hschool,description,diploma1,desc_d1,diploma2,desc_d2,diploma3,desc_d3,motivation_m1,motivation_m2,motivation_m3,motivation_m4);
exception
when no_data_found then
raise_application_error(-20017,'Vous n''etes pas un etudiant');
end;
/
This is the error message I am getting:
Errors for PROCEDURE OLD_CANDIDATE:
LINE/COL ERROR
-------- ---------------------------------------------
0/0 PLS-00801: internal error [phdite:node kind]
68/3 PL/SQL: SQL Statement ignored
69/110 PL/SQL: ORA-01775: looping chain of synonyms
72/4 PL/SQL: Statement ignored
I created some synonyms earlier and then dropped my tables and procedures and recreated them, I think this was the cause of the problem if I was not mistaken, can someone tell me how to fix this issue, or perhaps delete all synonyms? I tried dba_synonyms but I got that the table or view does not exist.

Resources