Problem with trigger and inserting data in oracle - oracle

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;

Related

ORA-01403: no data found ORA-06512: at line 8 01403. 00000 - "no data found"

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

Oracle Trigger To Check Values On Insert & Update

I am trying to check a value-gap crossed with each other or not. Let me explain with a quick scenario.
Rec 1 : Company AA : Distance Gap -> 100 - 200
Rec 2 : Company AA : Distance Gap -> 200 - 300 VALID
Rec 3 : Company AA : Distance Gap -> 250 - 450 INVALID
Rec 4 : Company JL : Distance Gap -> 250 - 450 VALID
Rec 3 Invalid because it is between REC 2's distance values.
Rec 4 Valid because company is different
Thus I wrote a trigger to prevent it.
create or replace trigger ab_redemption_billing_mpr
after insert or update on redemption_billing_mpr
for each row
declare
v_is_distance_range_valid boolean;
begin
v_is_distance_range_valid := p_redemption_billing.is_distance_range_valid(:new.id,
:new.redemption_billing_company,
:new.distance_min,
:new.distance_max,
'redemption_billing_mpr');
if not v_is_distance_range_valid then
raise_application_error(-20001, 'This is a custom error');
end if;
end ab_redemption_billing_mpr;
FUNCTION:
function is_distance_range_valid(p_id in number,
p_company in varchar2,
p_distance_min in number,
p_distance_max in number,
p_table_name in varchar2) return boolean is
d_record_number number;
begin
execute immediate 'select count(*) from ' || p_table_name || ' r
where r.redemption_billing_company = :1
and (:2 between r.distance_min and r.distance_max or :3 between r.distance_min and r.distance_max)
and r.id = nvl(:4, id)'
into d_record_number
using p_company, p_distance_min, p_distance_max, p_id;
if (d_record_number > 0) then
return false;
else
return true;
end if;
end;
is_distance_range_valid() works just as I expected. If it returns false, that means range check is not valid and don't insert or update.
When I create a scenario to catch this exception, oracle gives
ORA-04091: table name is mutating, trigger/function may not see it
and it points select count(*) line when I click debug button.
I don't know why I am getting this error. Thanks in advance.
Just check whether the below approach resolves your issue
Create a log table with columns required for finding the is_distance_range_valid validation and In your trigger insert into this log tab.The trigger on main table has to be a before insert or update trigger
Create a trigger on this log table and do the validation in the log table trigger and raise error.The trigger on log table has to be an after insert or update trigger.
Also this will only work if the row is already existing in the main table and it is not part of the current insert or update. If validation of the current insert or update is required then we need to use the :new.column_name to do the validation
Test:-
create table t_trg( n number);
create table t_trg_log( n number);
create or replace trigger trg_t
before insert or update on t_trg
for each row
declare
l_cnt number;
begin
insert into t_trg_log values(:new.n);
end trg_t;
create or replace trigger trg_t_log
after insert or update on t_trg_log
for each row
declare
l_cnt number;
begin
select count(1) into l_cnt from t_trg
where n=:new.n;
if l_cnt > 0 then
raise_application_error(-20001, 'This is a custom error');
end if;
end trg_t_log;
The first time I insert it doesn't throw error
insert into t_trg values(7);
1 row inserted.
The second time I execute, I get the custom error
insert into t_trg values(7);
Error report -
ORA-20001: This is a custom error
ORA-06512: at "TRG_T_LOG", line 7
ORA-04088: error during execution of trigger 'TRG_T_LOG'
ORA-06512: at "TRG_T", line 4
ORA-04088: error during execution of trigger 'TRG_T'
Update:-Using compound trigger the error is thrown in the first time the insert is done since it also takes into account the current row that we are updating or inserting while doing the SELECT
First I want to thanks to psaraj12 for his effort.
I found solution. Oracle forces us to not use select query before each row.
Oracle trigger error ORA-04091
So I wrote this and it works.
create or replace trigger ab_redemption_billing_mpr
for insert or update on redemption_billing_mpr
compound trigger
v_is_distance_range_valid boolean;
id redemption_billing_mpr.id%type;
redemption_billing_company redemption_billing_mpr.redemption_billing_company%type;
distance_min redemption_billing_mpr.distance_min%type;
distance_max redemption_billing_mpr.distance_max%type;
after each row is
begin
id := :new.id;
redemption_billing_company := :new.redemption_billing_company;
distance_min := :new.distance_min;
distance_max := :new.distance_max;
end after each row;
after statement is
begin
v_is_distance_range_valid := p_redemption_billing.is_distance_range_valid(id,
redemption_billing_company,
distance_min,
distance_max,
'redemption_billing_mpr');
if not v_is_distance_range_valid then
raise_application_error(-20001, 'This is a custom error');
end if;
end after statement;
end ab_redemption_billing_mpr;
We must use compound trigger to deal with it.

Impede the database writing with a trigger

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.

PL/SQL Error Return Multiple Rows

I want to store some results in a temp table after I update a table but it is giving me an error for categories/book types that have multiple entries. Everything works fine when I try to do it with a book type that has one entry. Can someone tell me how I would fix this, I think it's got something to do with not having a filter although I'm not sure how I would do that.
DROP PROCEDURE UpdateAdvance;
CREATE OR REPLACE PROCEDURE UpdateAdvance (
p_BookType titles.category%TYPE,
p_NewAdvance advance_temptable.new_advance%TYPE) AS
CURSOR titles_cur IS
SELECT *
FROM titles
WHERE category=p_BookType
FOR UPDATE OF advance;
titles_rec titles_cur%ROWTYPE;
v_OldAdvance titles.advance%TYPE;
v_TitleID titles.title_id%TYPE;
v_Title titles.title%TYPE;
BEGIN
SELECT advance, title_id, title
INTO v_OldAdvance, v_TitleID, v_Title
FROM titles
WHERE category=p_BookType;
FOR titles_rec in titles_cur LOOP
INSERT INTO advance_temptable VALUES(advance_sequence.nextval, v_TitleID, v_Title, v_OldAdvance, p_NewAdvance);
END LOOP;
COMMIT;
END UpdateAdvance;
When I call it like this
BEGIN
UpdateAdvance('psychology', 100);
END;
I get the error:
Error starting at line : 35 in command -
BEGIN
UpdateAdvance('psychology', 100);
END;
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SYSTEM.UPDATEADVANCE", line 14
ORA-06512: at line 2
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
Applied solution and here is what I now have working.
DROP PROCEDURE UpdateAdvance;
CREATE OR REPLACE PROCEDURE UpdateAdvance (
p_BookType titles.category%TYPE,
p_NewAdvance advance_temptable.new_advance%TYPE) AS
BEGIN
INSERT INTO advance_temptable
select advance_sequence.nextval, title_id, title, advance, p_NewAdvance
FROM titles
WHERE category=p_BookType;
COMMIT;
END UpdateAdvance;
BEGIN
UpdateAdvance('psychology', 100);
END;
Why don't you do:
INSERT INTO advance_temptable
select advance_sequence.nextval, TitleID, Title, Advance, p_NewAdvance
FROM titles
WHERE category = p_BookType;
without cursor?

PLSQL: BEFORE INSERT TRIGGER (check value in column from other table before allowing insert)

I've made a simple DVD store database. The DVD table has a column "status" which can be either 'FOR_RENT','FOR_SALE','RENTED',or 'SOLD'. I want to write a trigger to block any insertions into my RENTALS table if the status column in the DVD table is not set to 'FOR_RENT'.
Much of the documents I've looked at generally don't show example using values from two different tables so I'm a bit flummaxed.
This is what I believe has been my best attempt so far:
CREATE OR REPLACE TRIGGER RENTAL_UNAVAILABLE
BEFORE INSERT ON RENTAL;
FOR EACH ROW
WHEN (DVD.STATUS != 'FOR_RENT')
DECLARE
dvd_rented EXCEPTION;
PRAGMA EXCEPTION_INIT( dvd_rented, -20001 );
BEGIN
RAISE dvd_rented;
EXCEPTION
WHEN dvd_rented THEN
RAISE_APPLICATION_ERROR(-20001,'DVD has been rented');
END;
/
I'm getting this error:
ORA-00911: invalid character
Try this - I have not complied the code, but should be good. In case you see any compilation issues let me know and post schema on sqlfiddle.com
CREATE OR REPLACE TRIGGER rental_unavailable
BEFORE INSERT
ON rental
FOR EACH ROW
DECLARE
dvd_rented EXCEPTION;
PRAGMA EXCEPTION_INIT (dvd_rented, -20001);
n_count NUMBER (1);
BEGIN
SELECT COUNT (*)
INTO n_count
FROM dvd
WHERE dvd_id = :NEW.dvd_id AND dvd.status = 'FOR_RENT' AND ROWNUM < 2;
IF n_count > 0
THEN
RAISE dvd_rented;
END IF;
EXCEPTION
WHEN dvd_rented
THEN
raise_application_error (-20001, 'DVD has been rented');
END;

Resources