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
Related
Normally this basic If statement should return data but I don't understand, where I have made a mistake. (CustNo is char(8).) I think the problem occurs because of V_Id. In an usual select statement with this Custno='C2388597', I can have the data.But when it is in If statement, It gives the ORA-01403 Error code.
Thank you in advance for your Support...
Declare
V_Id Deneme_Customer.Custno%type;
V_Custbal Deneme_Customer.Custbal%Type;
v_situation Deneme_Customer.Custbal_Situation%type;
Begin
Select Custno, Custbal, Custbal_Situation Into V_Id, V_Custbal, V_Situation
From Deneme_Customer Where V_Id ='&no';
If (V_Custbal>=20 And V_Custbal<=100) Then
V_Situation:='Es tut mir sehr leid';
Elsif (V_Custbal>=101 And V_Custbal<=1000) Then
V_Situation:='Guuuut';
Elsif (V_Custbal>1000) Then
V_Situation:='Sehr Guuuut';
Else Dbms_Output.Put_Line('Falsche Eingabe');
End If;
update Deneme_Customer set Custbal_Situation=v_situation where Custno=V_Id;
end;`
I suppose v_id,which is a local variable, is Custno,which is a column of your table, on the 8th line.
An exception handling might still be needed for non-matching values for Custno vs. '&no' such as
Begin
Select Custno, Custbal, Custbal_Situation Into V_Id, V_Custbal, V_Situation
From Deneme_Customer
Where Custno = '&no';
Exception When no_data_found then null;
End;
Instead of using PL/SQL to determine what custbal_situation should be set to, you can do it easily with a simple update statement like this one:
UPDATE deneme_customer
SET custbal_situation =
CASE
WHEN custbal >= 20 AND custbal <= 100 THEN 'Es tut mir sehr leid'
WHEN custbal >= 101 AND custbal <= 1000 THEN 'Guuuut'
WHEN custbal > 1000 THEN 'Sehr Guuuut'
END
WHERE custbal >= 20;
If you want to modify it to only affect one customer, just add that to the where clause.
Then to see any customers that would not have their value set, you can find them with a query like this one
SELECT custno, custbal, custbal_situation
FROM deneme_customer
WHERE custbal < 20;
looks like you may not have any row matching Where V_Id ='&no', just to test it do a select count from the table Where V_Id ='&no'and check the count.
ALso is your V_Id a unique column, if not then you need to handle in your error handler the case when you fine more than one row matching your where clause.
exception
when no_data_found then
<handle apppropriately>
when TOO_MANY_ROWS then
<handle apppropriately>
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE
('Unknown error');
end
When I create the below tables and trigger, I'm getting a compiling bad bind error.
CREATE TABLE cteam_ExpenseItem (
ExpenseNo NUMBER
);
CREATE TABLE cteam_ExpenseReport (
ERSubmitNo NUMBER
);
CREATE OR REPLACE TRIGGER cteam_Trigger3
BEFORE INSERT OR UPDATE OF ExpenseNo ON cteam_ExpenseItem
FOR EACH ROW
DECLARE
vA cteam_ExpenseItem.ExpenseNo%TYPE;
BEGIN
SELECT ExpenseNo
INTO vA
FROM cteam_ExpenseItem
WHERE ExpenseNo = :NEW.ERSubmitNo;
IF vA <= ERSubmitNo THEN
RAISE_APPLICATION_ERROR(-20000, 'Error');
END IF;
END;
I'm getting a bad bind error for 'NEW.ERSUBMITNO'.
How do I go about solving this?
As #stickybit pointed out in a comment, there is no ERSubmitNo column on cteam_ExpenseItem. But even if there was, you don't want to try reading from the table your trigger is defined on - you're likely to get a TABLE IS MUTATING, TRIGGER CANNOT SEE IT error. Instead, use the value from the :OLD pseudo-row:
CREATE OR REPLACE TRIGGER cteam_Trigger3
BEFORE INSERT OR UPDATE OF ExpenseNo ON cteam_ExpenseItem
FOR EACH ROW
DECLARE
vA cteam_ExpenseItem.ExpenseNo%TYPE;
BEGIN
IF :OLD.ExpenseNo <= :NEW.ExpenseNo THEN
RAISE_APPLICATION_ERROR(-20000, 'Error');
END IF;
END;
I'm guessing that's what you're trying to do - if not you can fold, spindle, or mutilate as necessary. :-)
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;
I wrote this trigger to impede the database's writing
create or replace trigger spese_autorizzate_trg
before insert or update on spese
for each row
declare
boolean integer := 0;
voceSpesa tipospesa.descrizione%TYPE := NULL;
begin
select
descrizione into voceSpesa
from
tipospesa
where
id = :new.tipospesa
and approvazione = 'n';
if voceSPesa is NULL then
raise_application_error(-20000, 'La spesa '||voceSpesa||' non è rimborsabile');
end if;
end;
If the value of tipospesa is 4 or 5, the writing should be impeded
but when I insert a row like this
insert into spese(id, importo, tipospesa, data) values (4, 20, 3, TO_DATE('15-jul-18', 'DD-MON-RR'))
I have this error
Error report:
SQL Error: ORA-01403: no data found
ORA-06512: at "PARLAMENTO2018.SPESE_AUTORIZZATE_TRG", line 7
ORA-04088: error during execution of trigger
'PARLAMENTO2018.SPESE_AUTORIZZATE_TRG'
01403. 00000 - "no data found"
*Cause:
*Action:
and the writing isn't done. Why?
To me, it seems that you'd have to handle NO_DATA_FOUND, instead of handling possibility that DESCRIZIONE is NULL. Something like this:
create or replace trigger spese_autorizzate_trg
before insert or update on spese
for each row
declare
-- boolean integer := 0; -- Uh, no! Boolean is name of PL/SQL datatype;
-- don't use it as name of a variable
-- Besides, it is never used in your code.
voceSpesa tipospesa.descrizione%TYPE; -- No need to set it to NULL explicitly;
-- it is NULL anyway
begin
select descrizione
into voceSpesa
from tipospesa
where id = :new.tipospesa
and approvazione = 'n';
exception
when no_data_found then
raise_application_error(-20000, 'La spesa '||voceSpesa||' non è rimborsabile');
when too_many_rows then
-- what then? Do you know? Can that select return more than a single row? If so,
-- you should handle it
null;
end;
True, you could save some typing by using select max(descrizione) ..., but that's kind of tricky. If someone else inherits your code, will they know that you used MAX to avoid NO_DATA_FOUND, or whether you intentionally meant to select the largest value of that column? Therefore, I'd say that it is better to actually handle exceptions you expect and avoid any doubt.
The problem is that an INTO clause will fail if no rows are returned from the table, raising no_data_found
MAX or MIN may be used to give you a NULL in case there were no rows.
select
MAX(descrizione) into voceSpesa
from
tipospesa
where
id = :new.tipospesa
and approvazione = 'n';
Do remember that this will also have null in cases where the column descrizione itself is null. But, it purely depends on your requirement how you would like to handle that situation if it ever occurs.
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.