I want to have a trigger that no more than 3 employees work on a given project this is the code that i have but doesn’t work very well, sometimes work and sometimes doesn’t work.
create or replace trigger t_maxim_empleats_projecte before insert or update of codi_proj on empleats for each row declare contador number(5); begin select count(codi_proj) into contador from empleats where codi_proj= :new.codi_proj; if contador > 3 then RAISE_APPLICATION_ERROR(-20000, 'No poden haver-hi més de 3 empleats en un mateix projecte.'); end if; end;
This is all i have in my SQL tables:
create table Projectes( codi_proj number(5), nom_proj varchar2(25), pressupost number(10,2), primary key (codi_proj) ); create table Empleats( codi_emp number(5), nom_emp varchar2(15), sou number(10,2), codi_dept number(5), codi_proj number(5), data_alta date, primary key (codi_emp), foreign key (codi_dept) references Departaments(codi_dept) on delete set null, foreign key (codi_proj) references Projectes(codi_proj) on delete set null ); insert into projectes(codi_proj, nom_proj, pressupost) values (1, 'Daisy', 240000); insert into projectes(codi_proj, nom_proj, pressupost) values (2, 'CLAM', 63000); insert into projectes(codi_proj, nom_proj, pressupost) values (3, 'Vocal Processor', 600000); insert into empleats(codi_emp, nom_emp, sou, codi_dept, codi_proj,data_alta) values (1, 'Maria', 21000, 1, 1,TO_DATE('10/10/1980','dd/mm/yyyy')); insert into empleats(codi_emp, nom_emp, sou, codi_dept, codi_proj,data_alta) values (2, 'Josep', 18000, 1, 1,TO_DATE('01/08/1982','dd/mm/yyyy')); insert into empleats(codi_emp, nom_emp, sou, codi_dept, codi_proj,data_alta) values (3, 'Ramon', 48000, 4, 2,TO_DATE('05/04/2005','dd/mm/yyyy'));
Advertisement
Answer
You are not going to do what you want at least with the current row level trigger approach. The reason being that a row level trigger can not access the table that caused it to fire. As a result the statement “select … from empleats … will throw the exception “ORA-04091: table is mutating, trigger/function may not see it” because the trigger fires in response to DML against table empleats. A better process is to make this check in a Business Rules layer, or even the application level. However, if you insist on a trigger, it can be accomplished via an after statement trigger. That trigger does have to (or at least should) deal with possibility multiple projects exceeding the max employee limit. So (See fiddle):
create or replace trigger limit_3_emp_per_proj_ais after insert on employees declare k_new_msg_line constant varchar2(3) := chr(10) || ' '; k_max_emp_message constant varchar2(80) := 'No rows inserted!' || k_new_msg_line || 'Following Projects have exceed max of 3 employees:'; cursor proj_over_3_emp is select proj.name, proj.proj_id, count(*) from projects proj join employees emp on (emp.proj_id = proj.proj_id) group by proj.proj_id, proj.name having count(*) > 3 order by proj.proj_id; l_proj_exceeds_3_emp varchar2(3500) := null; begin for proj_emp in proj_over_3_emp loop l_proj_exceeds_3_emp := l_proj_exceeds_3_emp || k_new_msg_line || proj_emp.name || '(' || proj_emp.proj_id || ')'; end loop; if l_proj_exceeds_3_emp is not null then raise_application_error( -20199,k_max_emp_message || l_proj_exceeds_3_emp); end if; end limit_3_emp_per_proj_ais;