I have a problem here with a trigger. The purpose of the trigger is to verify that the client associated with a car registration, paid or not paid the bill in a workshop. If the client has paid all, then it is created a new service order (so far runs), but then paid the account is not possible to create a work order. So here the problem arises when I try to insert a service.
This is what's causing the trigger to fire:
INSERT INTO ORDEM(cod_ordem,data,codigo_func_m,tipo_ordem,matricula,estado_ordem)
VALUES(to_char(seq_cod_ordem.nextval),to_date('23/11/2014','dd/mm/yyyy'),'2','Serviço','66-AB-00','Pendente')
and I get this error after the execution:
Error starting at line : 140 in command -
INSERT INTO ORDEM(cod_ordem,data,codigo_func_m,tipo_ordem,matricula,estado_ordem)
VALUES(to_char(seq_cod_ordem.nextval),to_date('23/11/2014','dd/mm/yyyy'),'2','Serviço','66-AB-00','Pendente')
Error report -
SQL Error: ORA-01403: não foram encontrados dados
ORA-06512: na "BD1415_DC5.SALDO_CLIENTE_OFICINA", linha 7
ORA-04088: erro durante a execução do trigger 'BD1415_DC5.SALDO_CLIENTE_OFICINA'
01403. 00000 - "no data found"
*Cause:
*Action:
This is my code:
create or replace TRIGGER saldo_cliente_Oficina
BEFORE INSERT ON ORDEM
FOR EACH ROW
DECLARE
t_codigo_cliente CLIENTES.codigo_cliente%TYPE;
t_estado BOOLEAN := TRUE;
t_excecao EXCEPTION;
BEGIN
SELECT DISTINCT codigo_cliente INTO t_codigo_cliente
FROM ORDEM, VEICULO
WHERE (ORDEM.matricula = :NEW.matricula) AND (ORDEM.matricula = VEICULO.matricula);
FOR t_estado_fact IN (SELECT FACTURA.numero_factura,FACTURA.codigo_cliente,FACTURA.estado FROM FACTURA,CLIENTES
WHERE CLIENTES.codigo_cliente = t_codigo_cliente AND CLIENTES.codigo_cliente = FACTURA.codigo_cliente)LOOP
IF t_estado_fact.estado = 'Não Paga' THEN
t_estado := FALSE;
END IF;
IF t_estado = FALSE THEN
RAISE t_excecao;
END IF;
END LOOp;
EXCEPTION
WHEN t_excecao THEN
RAISE_APPLICATION_ERROR(-20001, 'O Proprietário do veiculo que pretende criar uma ordem, deve serviços a Oficina.');
END saldo_cliente_Oficina;
The below select in the trigger is returning no rows.In this case the first insert in ORDEM for a particular matricula will always fail.
SELECT DISTINCT codigo_cliente INTO t_codigo_cliente
FROM ORDEM, VEICULO
WHERE (ORDEM.matricula = :NEW.matricula) AND (ORDEM.matricula = VEICULO.matricula);
Kindly try changing this to the below
SELECT DISTINCT codigo_cliente INTO t_codigo_cliente
FROM VEICULO
WHERE VEICULO.matricula=:NEW.matricula;
Related
I'm a student and I have this exercise: we have to write a function with 2 parameters, account number and withdrawal, and return the new balance of a bank account only if the account balance - withdrawal > Flow threshold
This is my code:
set serveroutput on
CREATE OR REPLACE FONCTION Retrait
(f_numcomp in varchar2,f_montant NUMBER(38,3))
RETURN NUMBER(38,3)
AS
v_compte compte%rowtype;
v_solde compte.Solde%type;
BEGIN
SELECT * into v_compte from compte where f_numcomp = compte.NUMEROCOMPTE;
if (v_compte.Solde - f_montant) > v_compte.SeuilDebit /*and compte.Etat != 'desactiver'*/ THEN
v_solde := v_compte.Solde - f_montant;
UPDATE compte SET Solde = Solde - f_montant where f_numcomp = compte.NumeroCompte;
else
dbms_output.put_line('solde insufusant!');
end if;
return(v_solde);
END Retrait;
/
This is what I get:
Rapport d'erreur -
ORA-06550: Ligne 9, colonne 16 :
PLS-00103: Symbole "(" rencontré à la place d'un des symboles suivants :
. ;
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I'm new here; I read some articles here but still didn't find the error
You should be able to simplify the function to use a single UPDATE statement with a RETURNING clause (rather than SELECT and then UPDATE):
CREATE FUNCTION Retrait (
f_numcomp IN COMPTE.NUMEROCOMPTE%TYPE,
f_montant IN COMPTE.SOLDE%TYPE
) RETURN COMPTE.SOLDE%TYPE
AS
v_solde COMPTE.SOLDE%TYPE;
BEGIN
UPDATE compte
SET Solde = Solde - f_montant
WHERE f_numcomp = NumeroCompte
AND solde - f_montant > SeuilDebit
RETURNING solde INTO v_solde;
IF SQL%ROWCOUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('solde insufusant!');
END IF;
RETURN v_solde;
END Retrait;
/
However, it is not usual to have DML statements in a function; you would normally use a PROCEDURE and have an OUT parameter to return the value.
fiddle
FONCTION must be FUNCTION, but that was obviously just a typo in the request here, because the error you got is something else.
In the function declaration Oracle wants types without precision. I.e. NUMBER instead of NUMBER(38, 3).
CREATE OR REPLACE FUNCTION Retrait (f_numcomp IN VARCHAR2, f_montant NUMBER)
RETURN NUMBER
AS
v_compte compte%ROWTYPE;
v_solde compte.Solde%TYPE;
BEGIN
SELECT * INTO v_compte
FROM compte
WHERE f_numcomp = compte.NUMEROCOMPTE;
...
I am getting no data found error in pl/sql
Actually problem is in the trigger
I want to use NO_DATA_FOUND error in the elsif statement
alter table SUPPLIER add trusted_supplier VARCHAR(30)
and then update it with the data that I load in the table
UPDATE SUPPLIER SET trusted_supplier ='Exotic Liquids'
while using the select statement I have only one value in the trusted_supplier so if insert value in the product is not equal to that
trusted supplier value I am getting error as no data found
is there any way i use NO_DATA_FOUND error which is predefined in pl/sql in the else if statement
CREATE OR REPLACE TRIGGER CHECK_SUPPLIER
BEFORE INSERT ON PRODUCT
FOR EACH ROW
DECLARE
supplier_info varchar(400);
except1 exception;
begin
select SUPPLIER_NAME
INTO supplier_info
FROM PRODUCT P JOIN SUPPLIER S
ON S.COMPANY_NAME = P.SUPPLIER_NAME
where S.trusted_supplier = :NEW.SUPPLIER_NAME ; here
if(supplier_info = 'Exotic Liquids') then
dbms_output.put_line('trusted supplier')
elsif
---------here
END IF;
exception
when except1 then
dbms_output.put_line('its not the trusted supplier');
END;
/
I got a problem with trigger whem im trying to insert data to table
CREATE OR REPLACE TRIGGER OGRANICZ
BEFORE INSERT ON BILET
FOR EACH ROW
DECLARE
counter NUMBER(6);
check NUMBER(6);
BEGIN
SELECT id_seans INTO counter FROM seans WHERE id_seans=:NEW.id_seans AND EXTRACT(YEAR FROM data) = 2020;
SELECT COUNT(*) INTO counter FROM BILET B WHERE B.id_seans=:NEW.id_seans;
IF (check = :NEW.id_seans AND counter >=3) THEN
RAISE_APPLICATION_ERROR(-20001, 'too many');
ELSIF(check <> :NEW.id_seans AND counter >=2) THEN
RAISE_APPLICATION_ERROR(-20002, 'too many');
END IF;
END;
I have to set limit for my table that i cant add to many values with the same value for id_seans in bilet table. When im adding too many values for first value of id_seans it works. But if im trying to add any value for other id_seans there is error like this
ORA-01403: no data found ORA-06512: at "SQL_OXRLEFMPXILAXVNAWVBOUVDFO.OGRANICZ", line 6
ORA-06512: at "SYS.DBMS_SQL", line 1721
NO_DATA_FOUND exception might only raise due to the first SELECT statement, while the second one returns an integer starting from zero for any case. So, it's sufficient to handle that exception for the first one in a such a way that
BEGIN
SELECT id_seans
INTO counter
FROM seans
WHERE id_seans=:new.id_seans
AND EXTRACT(YEAR FROM data) = 2020;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
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 am developing a trigger that keeps a table updated where the departments are recorded and the total sum of their salaries. Each time the EMP table is updated. The trigger updates this table. To avoid the error of mutant tables, I have implemented a "COMPOUND TRIGGER" type trigger.
Here I put your implementation:
CREATE OR REPLACE TRIGGER EJERCICIO_27
FOR INSERT OR UPDATE OR DELETE ON EMP
COMPOUND TRIGGER
TYPE t_DeptToUpdate IS TABLE OF NUMBER(2,0);
deptToUpdate t_DeptToUpdate;
-- AFTER EACH ROW Section:
AFTER EACH ROW IS
BEGIN
IF NOT :OLD.DEPTNO MEMBER OF deptToUpdate THEN
deptToUpdate.EXTEND;
deptToUpdate(deptToUpdate.LAST) := :OLD.DEPTNO;
END IF;
END AFTER EACH ROW;
-- AFTER STATEMENT Section:
AFTER STATEMENT IS
BEGIN
DBMS_OUTPUT.PUT_LINE('SE ACTUALIZAN UN TOTAL DE: ' || deptToUpdate.COUNT);
MERGE INTO SALARIO_DEPARTAMENTOS SD USING (
SELECT DEPTNO, NVL(SUM(SAL), 0) AS SUM_TOTAL FROM EMP
WHERE DEPTNO IN (SELECT * FROM TABLE(deptToUpdate))
GROUP BY DEPTNO
) D
ON (SD.DEPTNO = D.DEPTNO)
WHEN MATCHED THEN
UPDATE SET
SAL_TOT = D.SUM_TOTAL
WHERE SD.DEPTNO = D.DEPTNO
WHEN NOT MATCHED THEN
INSERT (DEPTNO, SAL_TOT)
VALUES(D.DEPTNO, D.SUM_TOTAL);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || SQLCODE || 'MENSAJE: ' || SQLERRM);
END AFTER STATEMENT;
END;
/
The problem I have when using the collection as a source for querying the MERGE statement. I understood that in Oracle 12c (I am using Oracle 12c R2 Enterprise) I could use the TABLE operator with locally defined types. As discussed in this post Using the TABLE Operator with Locally Defined Types in PL/SQL.
Exactly the errors that the compiler returns me are:
LINE/COL ERROR
-------- -----------------------------------------------------------------
20/5 PL/SQL: SQL Statement ignored
22/40 PL/SQL: ORA-22905: no se puede acceder a las filas de un elemento de tabla no anidada
22/46 PLS-00642: tipos de recopilación local no permitidos en sentencias SQL
Someone can tell me what approach to use without having to create any type in the schematic?. Thanks in advance.
EDIT
Translation of error messages:
ORA-22905: Rows of a non-nested table element can not be accessed
PLS-00642: Local collection types not allowed in SQL statements
Are you required to use a collection? If not, then it seems that a simple row-level trigger should work, something like this:
Create Or Replace Trigger emp_trig
After Insert Or Update Or Delete On emp
For Each Row
Begin
-- Subtract old salary from old department
Update department_salary ds
Set ds.tot_salary = ds.tot_salary - :old.salary
Where ds.dept = :old.dept;
If Inserting Or Updating Then
-- Add new salary to new department
Update department_salary ds
Set ds.tot_salary = ds.tot_salary + :new.salary
Where ds.dept = :new.dept;
If SQL%Rowcount = 0 Then
Insert Into department_salary (dept, tot_salary) Values(:new.dept, :new.salary);
End If;
End If;
End;
/
The separate update statements for old and new values handle cases when an updated row might contain a changed department number.
As LauDec commented, a very straightforward way to maintain a list of departments and total salary would be with a view such as this:
Create Or Replace View salario_departamentos_view As
Select deptno, Sum(sal) As sal_tot From emp
Group By deptno;
The beauty of this solution is that the data is always in perfect harmony with the EMP table, and it's very easy to understand, even for someone with minimal SQL skills.