Checking a trigger function - oracle

create or replace trigger addbook
before insert
on book
for each row
DECLARE
xcost float;
begin
select avg(cost) into xcost
from book;
if :new.cost > xcost then
INSERT INTO book (
book_no,
title,
cost
) VALUES (:new.book_no,
:new.title,
:new.cost
);
end if;
end addbook;
/
// .............. This is my trigger .It executed correctly but when I do the following:
SQL> INSERT INTO book (
2 book_no,
3 title,
4 cost
5 ) VALUES (104,
6 'C++ Brain work',
7 500
8 );
// ............I got error like this :
INSERT INTO book (
*
ERROR at line 1:
ORA-00036: maximum number of recursive SQL levels (50) exceeded
ORA-00036: maximum number of recursive SQL levels (50) exceeded
ORA-06512: at "EXP8.ADDBOOK", line 4
ORA-04088: error during execution of trigger 'EXP8.ADDBOOK'
ORA-06512: at "EXP8.ADDBOOK", line 8
// What I will do???????

Your trigger is triggering itself which causes a infinite loop and triggers the fail-safe protection showed. Either change your schema in order to record that changes in a second table or refactor your trigger to avoid entering in the infinite loop (additional column that according to its value would skip the second insertion)
I would prefer the first approach as it is much cleaner but I am speculating on your model.

Related

Insert the data by running trigger but after running the condition in Oracle

I am trying to insert data in the form of creating trigger. But before inserting the data into the table, I want to run one condition which is
want to delete the data with some condition. So I implemented like this below
Once the condition is true then only INSERT otherwise not.
create or replace TRIGGER APP_WFM.TRG_INS_NE_SF_SITE_INSTANCE
BEFORE INSERT OR UPDATE ON SF_NE_DETAILS
FOR EACH ROW
BEGIN
IF
DELETE FROM NE_SITE_INSTANCE
WHERE build_by IN ('RCOM','RJIL','IP1','IP1 COLO')
AND validation_status IS NULL
AND wfm_hoto_flag IS NULL;
THEN
INSERT INTO NE_SITE_INSTANCE (
rf_siteid,
sap_id,
sitename,
DSUPPLIERBATTERYBANK,
DUTILITYINSTBATTERYBANK,
DENDDGDATE,
DSTARTDGDATE,
DEMFEND,
DEMFSTART,
DQUALITYDATE,
DRFE1OFFERED,
DUTILITYINSTODC,
DSUPPLIERSMPS,
DUTILITYINSTSMPS,
DLTOWERPOLEMATERIAL,
DLNOOFPLATFORM,
DLNOOFPOLES,
DLNOOFSECTORS,
DLBATREDIFIER,
DLNOOFREDINSMPS,
FUBATCOMMREPORT,
FUDGCOMREPORT,
FUSMPSCOMREPORT,
DLSHELTER,
CANDIDATEID,
CIRCLE,
CITY_NAME,
LATITUDE,
LONGITUDE,
DLMATERIALSUPPLIER,
DLBATMODELNAME,
DBATRECTIFIERSRNO1,
DBATRECTIFIERSRNO2,
DBATRECTIFIERSRNO3,
DBATRECTIFIERSRNO4,
DBATRECTIFIERSRNO5,
DBATRECTIFIERSRNO6,
DCBMS,
DDGALTERNATEMAKE,
DGALTERNATESRNO,
DCRANKMAKE,
DCRANKSRNO,
DDCENGINEMAKE,
DDGENGINESRNO,
DLDGMODELNAME,
DLEARTHING,
DLRP1MODELNAME,
DCENERGYMETEROWNSRNO,
DLMODELFDPFDMS1_COUNT,
DLMODELFDPFDMS1,
DFDPMAKE,
DLMODELFDPFDMS_COUNT,
DLMODELFDPFDMS,
DODCMAKE,
DLDOCMODELNAME,
ODCSERIALNO,
DLGO,
DSHELTERMAKE,
DSHELTERSRNO,
DCONTROLLERADDRESS,
DSMPSMAKE,
DLMODELSMPS,
DPAUIPADDRESS,
DSMPSRECTIFIERSRNO1,
DSMPSRECTIFIERSRNO2,
DSMPSRECTIFIERSRNO3,
DSMPSRECTIFIERSRNO4,
DSMPSRECTIFIERSRNO5,
DSMPSRECTIFIERSRNO6,
DSMPSSRNO,
DLLTOWERTYPE,
DSUPPLIERFDMS,
DRFE1DECLARED,
SITE_TYPE,
DSMPSRECTIFIERSRNO7,
DSMPSRECTIFIERSRNO8,
DSMPSRECTIFIERSRNO9,
DSMPSRECTIFIERSRNO10,
DSMPSRECTIFIERSRNO11,
DSMPSRECTIFIERSRNO12,
ALARM_GATEWAY_MAKE,
ALARM_GATEWAY_MODEL_NAME,
ALRM_GTWAY_INTS_DT,
ALRM_GTWAY_SR_NO,
ALRM_GTWAY_COMM_DT
) VALUES (
:NEW.rf_siteid,
:NEW.sap_id,
:NEW.site_name,
:NEW.DSUPPLIERBATTERYBANK,
:NEW.DUTILITYINSTBATTERYBANK,
:NEW.DENDDGDATE,
:NEW.DSTARTDGDATE,
:NEW.DEMFEND,
:NEW.DEMFSTART,
:NEW.DQUALITYDATE,
:NEW.DRFE1OFFERED,
:NEW.DUTILITYINSTODC,
:NEW.DSUPPLIERSMPS,
:NEW.DUTILITYINSTSMPS,
:NEW.DLTOWERPOLEMATERIAL,
:NEW.DLNOOFPLATFORM,
:NEW.DLNOOFPOLES,
:NEW.DLNOOFSECTORS,
:NEW.DLBATREDIFIER,
:NEW.DLNOOFREDINSMPS,
:NEW.FUBATCOMMREPORT,
:NEW.FUDGCOMREPORT,
:NEW.FUSMPSCOMREPORT,
:NEW.DLSHELTER,
:NEW.CANDIDATEID,
:NEW.CIRCLE,
:NEW.CITY_NAME,
:NEW.LATITUDE,
:NEW.LONGITUDE,
:NEW.DLMATERIALSUPPLIER,
:NEW.DLBATMODELNAME,
:NEW.DBATRECTIFIERSRNO1,
:NEW.DBATRECTIFIERSRNO2,
:NEW.DBATRECTIFIERSRNO3,
:NEW.DBATRECTIFIERSRNO4,
:NEW.DBATRECTIFIERSRNO5,
:NEW.DBATRECTIFIERSRNO6,
:NEW.DCBMS,
:NEW.DDGALTERNATEMAKE,
:NEW.DGALTERNATESRNO,
:NEW.DCRANKMAKE,
:NEW.DCRANKSRNO,
:NEW.DDCENGINEMAKE,
:NEW.DDGENGINESRNO,
:NEW.DLDGMODELNAME,
:NEW.DLEARTHING,
:NEW.DLRP1MODELNAME,
:NEW.DCENERGYMETEROWNSRNO,
:NEW.DLMODELFDPFDMS1_COUNT,
:NEW.DLMODELFDPFDMS1,
:NEW.DFDPMAKE,
:NEW.DLMODELFDPFDMS_COUNT,
:NEW.DLMODELFDPFDMS,
:NEW.DODCMAKE,
:NEW.DLDOCMODELNAME,
:NEW.ODCSERIALNO,
:NEW.DLGO,
:NEW.DSHELTERMAKE,
:NEW.DSHELTERSRNO,
:NEW.DCONTROLLERADDRESS,
:NEW.DSMPSMAKE,
:NEW.DLMODELSMPS,
:NEW.DPAUIPADDRESS,
:NEW.DSMPSRECTIFIERSRNO1,
:NEW.DSMPSRECTIFIERSRNO2,
:NEW.DSMPSRECTIFIERSRNO3,
:NEW.DSMPSRECTIFIERSRNO4,
:NEW.DSMPSRECTIFIERSRNO5,
:NEW.DSMPSRECTIFIERSRNO6,
:NEW.DSMPSSRNO,
:NEW.DLLTOWERTYPE,
:NEW.DSUPPLIERFDMS,
:NEW.DRFE1DECLARED,
:NEW.SITE_TYPE,
:NEW.DSMPSRECTIFIERSRNO7,
:NEW.DSMPSRECTIFIERSRNO8,
:NEW.DSMPSRECTIFIERSRNO9,
:NEW.DSMPSRECTIFIERSRNO10,
:NEW.DSMPSRECTIFIERSRNO11,
:NEW.DSMPSRECTIFIERSRNO12,
:NEW.ALARM_GATEWAY_MAKE,
:NEW.ALARM_GATEWAY_MODEL_NAME,
:NEW.ALRM_GTWAY_INTS_DT,
:NEW.ALRM_GTWAY_SR_NO,
:NEW.ALRM_GTWAY_COMM_DT
);
END;
But its giving error as
Error(8,1): PLS-00103: Encountered the symbol "DELETE" when expecting one of the following: ( - + case mod new not null continue avg count current exists max min prior sql stddev sum variance execute forall merge time timestamp interval date pipe <an alternat
If the goal is to check whether the delete removed rows before running the insert, you'd want something like
create or replace TRIGGER APP_WFM.TRG_INS_NE_SF_SITE_INSTANCE
BEFORE INSERT OR UPDATE ON SF_NE_DETAILS
FOR EACH ROW
BEGIN
DELETE ...
IF( sql%rowcount > 0 )
THEN
INSERT ...
END IF;
END;
It's not obvious to me that this makes a whole lot of sense, though. If you run a SQL statement that inserts 1000 rows into SF_NE_DETAILS, you'd run the delete 1000 times (which seems inefficient) and insert only a single row into NE_SITE_INSTANCE. That seems unlikely to be what you really want. My guess is that you really want a statement-level trigger that does the delete
create or replace TRIGGER APP_WFM.TRG_INS_NE_SF_SITE_INSTANCE
BEFORE INSERT OR UPDATE ON SF_NE_DETAILS
BEGIN
DELETE ...
END;
and then the row-level trigger that just does the insert. Then in the case that you run an insert that inserts 1000 rows, you'd run the delete once and the insert 1000 times.
Of course, this assumes that there is a good reason that you need to have two tables that seem to consist of mostly duplicate information. That would make some sense if ne_site_instance was a history table but that doesn't appear to be what's going on here. Are you sure that you don't really want a view/ materialized view/ something else?

Trigger do not compile

I have a database that is made like this
works_on(ssn,project_number,hours)
and i have a trigger that asks me
that if an emp works more than 50 hours on a project it cannot be put on a 2 project.
if an emp works more than 70 hours on 2 projects it cannot be associated on a 3 project
an emp can only be associated to a max of 6 project
Sorry for my attempt i'm just learning how to make triggers. I have an error near the select statement:
Errore(8,6): PLS-00103: Encountered the symbol "SELECT" when expecting
one of the following: ( - + case mod new not null
continue
avg count current exists max min prior sql stddev sum variance
execute forall merge time timestamp interval date pipe <an alternat
My trigger so far:
create or replace trigger exe
before insert on worsk_on
for each row
declare
too_much_hours EXCEPTION;
no_hours_left EXCEPTION;
too_projects EXCEPTION;
begin
if hours>100
then raise too_much_hours;
end if;
elsif (select count(project_number),ssn,sum(hours) from worsk_on
where count(project_number) > 1 and (sum(hours)>100)
group by ssn,project_number)
then raise no_hours_left;
end if;
else count( porject_number)>6
then raise too_projects;
end if;
EXCEPTION
when too_much_hours then raise_application_error(-20000,'ore progetto sature');
when no_hours_left then raise_application_error(-19000,'ore progetti sature');
when too_projects then raise_application_error(-15151,'ore progetti sature');
There are many errors:
You have not declared a PL/SQL hours variable.
You are using SELECT inside an IF statement.
The SELECT statement does not have an INTO clause.
You are selecting all the ssn and project_number and do not have a filter to correlate it to the row being inserted.
You have spelling mistakes in worsk_on and porject_number.
The third COUNT( project_number ) is not valid as you are not in a SELECT statement.
You have elsif and else statements with no corresponding IF statement (as you have closed the previous statements with END IF.
There may be more (for example, if you fix all of them then I expect you'll get a mutating table exception as you are aggregating over the table you are inserting into.)

Warning: Trigger created with compilation error

I have two tables, seat_allocation and programme_code. I want to create a trigger for checking if the number of entries into the seat_allocation are equal to the max_seats(column in programm_code table) for that prog_code(column in programme_code table). This is my code:
SQL> create or replace trigger seats_full
2 before insert on seat_allocation
3 for each row
4 declare
5 cnt programme_code.max_seats%type;
6 max programme_code.max_seats%type;
7 begin
8 select count(*) into cnt from seat_allocation where prog_code=(select prog_code from programme_code where prog_code = :NEW.prog_code);
9 select max_seats into max from programme_code where prog_code=(select prog_code from programme_code where prog_code = :NEW.prog_code);
10 if max=cnt then
11 RAISE_APPLICATION_ERROR(-21000,'No vacant seats available');
12 end if;
13 end;
14 /
It gives Warning:Trigger created with compilation error. Can you please help me figure out what's wrong?
Variable name can'be MAX, it is reserved for the function with the same name. Change it to e.g. v_max_seats.
Apart from that, it seems that you're selecting from the seat_allocation table (line #8), while the trigger fires on insert on the same table. It'll cause the mutating table error so - you'll have to do something. Nowadays, it is a compound trigger that fixes that. If your database version doesn't support it, you'll use a package. There are examples on the Internet.
Also, why using a subquery? What's wrong with e.g.
select max_seats into v_max_seats from programme_code where prog_code = :new.prog_code

Updating more than 1 row - Oracle SQL Procedure

I was wondering if it was possible to update more than 1 row with a procedure, im not sure why this one isnt working. Its working only if theres only 1 row in my table. But if there's more than 1 row i get the usual error message :
ORA-01422: exact fetch returns more than requested number of rows
I'm honestly not sure why this isnt working. Is it possible a procedure cannot update more than 1 row at once ?
create or replace procedure TP3_SP_ARCHIVER_ENCAN
is
V_CURRENT_DATE date;
V_DATE_ENCAN date;
begin
select sysdate, DATE_FIN_ENC into V_CURRENT_DATE, V_DATE_ENCAN
from
TP2_ENCAN;
update TP2_ENCAN
set EST_ARCHIVEE_ENC = 1,
STATUT_ENC = 'Archivé'
where V_CURRENT_DATE - V_DATE_ENCAN > 60;
end TP3_SP_ARCHIVER_ENCAN;
/
I'm excepting to archive every ENCAN that has been closed for a duration of 60+ days. everytime i run this procedure i just want to update those.
Full error message :
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "C##JALAC144.TP3_SP_ARCHIVER_ENCAN", line 8
ORA-06512: at line 1
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
This line is your problem:
select sysdate, DATE_FIN_ENC into V_CURRENT_DATE, V_DATE_ENCAN from TP2_ENCAN;
You are selecting DATE_FIN_ENC into a scalar variable that can hold exactly one value. You can select "1" into "x". You can't select "1" and "2" into "x" at the same time. So you get the error you're getting.
If I understand your problem correctly, you probably want this, with no initial select:
update TP2_ENCAN
set EST_ARCHIVEE_ENC = 1,
STATUT_ENC = 'Archivé'
where SYSDATE - DATE_FIN_ENC > 60;
Via your code you just want to update record base on current date. Therefore, you do not need to use parameter. Using the update script is enough.
Create or replace procedure TP3_SP_ARCHIVER_ENCAN is:
begin
update TP2_ENCAN
set EST_ARCHIVEE_ENC = 1,
STATUT_ENC = 'Archivé'
where sysdate - DATE_FIN_ENC > 60;
end
TP3_SP_ARCHIVER_ENCAN;

Syntax Error In Oracle Function

I'm trying to make a function that does a simple insert into a table called poli, the purpose of this fuction:
returns 1 when it inserts the values to the table
in any other case it returns 0.
This is the code in oracle that i wrote:
CREATE OR REPLACE FUNCTION ADDPOLI
( ID IN NUMBER, NAME IN VARCHAR2 , LON IN FLOAT , LAT IN FLOAT , STATUS OUT NUMBER )
return status
IS cursor poli_count is select count(id) from poli;
BEGIN
declare number_of_cities int;
fetch poli_c into number_of_cities;
if number_of_cities<= 15 and number_of_cities>=0 then
insert into poli values(id,name,lat,lon);
return 1;
else
return 0;
end if;
END ADDPOLI;
i have a syntax error here: fetch poli_c into number_of_cities;
how can i fix it ?
Why you are using cursor to achieve this. Try below -
CREATE FUNCTION ADDPOLI(ID INT, NAME VARCHAR(255), LON FLOAT, LAT FLOAT)
RETURNS INT
BEGIN
declare number_of_cities int;
select count(id) into number_of_cities from poli;
if number_of_cities between 0 and 15 then
insert into poli values(id,name,lat,lon);
return 1;
else
return 0;
end if;
END
There is something more fundamentally of concern here. What happens when you deploy this function in a multi-user environment (which most databases typically will run in).
The logic of:
"Do I have less than 15 cities?"
"Yes, insert another row"
is more complex than first appears. Because if I have 10 sessions all currently running this function, you can end up with the following scenario:
I start with say 13 rows. Then this happens:
Session 1: Is there less than 15? Yes, do the insert.
Session 2: Is there less than 15? Yes, do the insert.
Session 3: Is there less than 15? Yes, do the insert.
Session 4: Is there less than 15? Yes, do the insert.
Session 5: Is there less than 15? Yes, do the insert.
...
and now Session 1 commits, and so forth for Session 2, 3, ....
And hence voila! You now have 18 rows in your table and everyone is befuddled as to how this happened.
Ultimately, what you are after is a means of enforcing a rule about the data ("max of 15 rows in table X"). There is a lengthy discussion about the complexities of doing that over at AskTOM
https://asktom.oracle.com/pls/asktom/asktom.search?tag=declarative-integrity

Resources