ORA-22903: MULTISET expression not allowed - oracle

I have a table which have a field as nested table. I have a trigger on the first table, but it does not work and results on a :ORA-22903: MULTISET expression not allowed
CREATE OR REPLACE TYPE DIA_T as object
(dia varchar2(9),
hora varchar2(6));
CREATE OR REPLACE TYPE DIA_TAB IS TABLE OF DIA_T;
CREATE TABLE T_TALLER(
PK NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
...
DIAS DIA_TAB,
FEC_INI DATE NOT NULL,
FEC_FIN DATE NOT NULL,
...
CONSTRAINT CST_PRIMKEY_TALLER PRIMARY KEY (PK),
...
) NESTED TABLE DIAS STORE AS DIAS_TAB;
My trigger is:
CREATE OR REPLACE TRIGGER TRG_TALLER_AU_FEC_FIN AFTER UPDATE OF FEC_FIN ON T_TALLER FOR EACH ROW
BEGIN
FOR REC IN (SELECT T.DIA , T.HORA
FROM TABLE(:NEW.DIAS) T) LOOP
dbms_output.put_line(REC.DIA||' '||REC.HORA);
END LOOP;
END;
When I try something like that:
update t_taller set fec_fin = fec_fin + 20 where pk = 10;
I get the following error:
ORA-22903: MULTISET expression not allowed
ORA-06512: at "ESTAMPAS.TRG_TALLER_AU_FEC_FIN", line 3
ORA-04088: error during execution of trigger 'ESTAMPAS.TRG_TALLER_AU_FEC_FIN'
Can you help me to solve this problem?
Thanks in advance.
Regards,
UPDATE
The trigger I posted is a dummy, but the error i get for the real one is the same, my real trigger is this
CREATE OR REPLACE TRIGGER TRG_TALLER_AU_FEC_FIN AFTER UPDATE OF FEC_FIN ON T_TALLER FOR EACH ROW
BEGIN
IF :NEW.FEC_FIN >= :OLD.FEC_FIN THEN
Pkg_Utilidades.p_ins_taller_clase_grupo(:NEW.PK,(:OLD.FEC_FIN) + 1,:NEW.FEC_FIN,:NEW.DIAS,:NEW.AU_USU_INS);
ELSE
DELETE T_TALLER_CLASE
WHERE FK_TALLER = :NEW.PK
AND FEC_CLASE BETWEEN :NEW.FEC_FIN + 1 AND :OLD.FEC_FIN;
END IF;
END;
Something else to say, I have a "AFTER INSERT" Trigger, and it Works fine:
CREATE OR REPLACE TRIGGER TRG_TALLER_AI_CLASE AFTER INSERT ON T_TALLER FOR EACH ROW
BEGIN
DELETE T_TALLER_CLASE WHERE FK_TALLER = :NEW.PK;
Pkg_Utilidades.p_ins_taller_clase_grupo(:NEW.PK,:NEW.FEC_INI,:NEW.FEC_FIN,:NEW.DIAS,:NEW.AU_USU_INS);
END;
The procedure is:
PROCEDURE p_ins_taller_clase_grupo (p_taller NUMBER,
p_fec_ini DATE,
p_fec_fin DATE,
p_dias DIA_TAB,
p_user VARCHAR2) IS
p_output VARCHAR2(100);
v_dia NUMBER;
BEGIN
FOR REC IN (SELECT p_fec_ini + LEVEL - 1 FECHA,
DECODE(TO_CHAR(p_fec_ini + LEVEL - 1 , 'DAY'),'MONDAY ',1,'TUESDAY ',2,'WEDNESDAY',3,'THURSDAY ',4,'FRIDAY ',5,'SATURDAY ',6,7) DIA
FROM DUAL
CONNECT BY LEVEL <= p_fec_fin - p_fec_ini + 1) LOOP
BEGIN
SELECT D INTO v_dia
FROM (
SELECT decode(upper(T.dia),'LUNES',1,'MARTES',2,'MIERCOLES',3,'MIÉRCOLES',3,'JUEVES',4,'VIERNES',5,'SABADO',6,'SÁBADO',6,7) D
FROM TABLE(p_dias) T
)
WHERE D = REC.DIA;
P_INS_TALLER_CLASE (p_taller,REC.FECHA,Pkg_conf.CST_HORA,p_user,p_output);
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
END LOOP;
END p_ins_taller_clase_grupo;
The insert Works fine:
SQL> insert into t_taller (FK_profesor,fk_danza,fk_local,fk_periodicidad,fec_ini,fec_fin,dias,AU_USU_INS) values (1,1,1,1,to_date('05/01/2019','dd/mm/yyyy'),to_date('27/01/2019','dd/mm/yyyy'),dia_tab(dia_t('SABADO','10:30'),dia_t('DOMINGO','10:30')),'EP_PL01');
1 row created.
SQL> commit;
Commit complete.
SQL> update t_taller set fec_fin = fec_fin + 20 where pk = 24;
update t_taller set fec_fin = fec_fin + 20 where pk = 24
*
ERROR at line 1:
ORA-22903: MULTISET expression not allowed
ORA-06512: at "ESTAMPAS.PKG_UTILIDADES", line 451
ORA-06512: at "ESTAMPAS.TRG_TALLER_AU_FEC_FIN", line 5
ORA-04088: error during execution of trigger 'ESTAMPAS.TRG_TALLER_AU_FEC_FIN'
The line 451 of the package, is inside the procedure, exactly here:
SELECT D INTO v_dia
FROM (
SELECT decode(upper(T.dia),'LUNES',1,'MARTES',2,'MIERCOLES',3,'MIÉRCOLES',3,'JUEVES',4,'VIERNES',5,'SABADO',6,'SÁBADO',6,7) D
FROM TABLE(p_dias) T
)
WHERE D = REC.DIA;
Sorry for not posted all the details from the begining, i wanted to summayrize and show just the error.
Regards

TABLE expression works if you are running a select query on the table itself.
Something like
SELECT T.DIA , T.HORA
FROM T_TALLER ,TABLE(:NEW.DIAS) T
But, you are not allowed to select from the Trigger owner as it leads to "table is mutating" error( ORA-04091 ).
You may instead loop through the nested table column using a simple for loop.
CREATE OR REPLACE TRIGGER trg_taller_au_fec_fin AFTER
UPDATE OF fec_fin ON t_taller
FOR EACH ROW
BEGIN
FOR i in 1 .. :new.dias.count
LOOP
dbms_output.put_line(:new.dias(i).dia || ' ' || :new.dias(i).hora);
END LOOP;
END;
/
By the way, as #XING mentioned, there's no use of dbms_output in a Trigger. You should rather consider logging them into a table.
Demo

As mentioned in my comments Triggers are used for handling of events on the table to . Although your posted script does not make much sense to me , however am giving the solution.
Also you simply cannot Select records from a Nested table. You need to use table operator to do so. Also in a trigger if you do Select on same table, you might land up is mutating, trigger/function. See below demo:
CREATE OR REPLACE TYPE dia_t AS OBJECT (
dia VARCHAR2(9),
hora VARCHAR2(6)
);
CREATE OR REPLACE TYPE DIA_TAB IS TABLE OF DIA_T;
CREATE TABLE t_taller (
pk NUMBER ,
dias dia_tab,
fec_ini DATE NOT NULL,
fec_fin DATE NOT NULL,
CONSTRAINT cst_primkey_taller PRIMARY KEY ( pk )
)
NESTED TABLE dias STORE AS dias_tab;
INSERT INTO t_taller VALUES (
1,
dia_tab(dia_t(
'A',
'B')
),
TO_DATE('10-Dec-2018','DD-Mon-YYYY'),
TO_DATE('10-Dec-2018','DD-Mon-YYYY')
);
CREATE OR REPLACE TRIGGER trg_taller_au_fec_fin
AFTER UPDATE OF fec_fin ON t_taller
FOR EACH ROW
BEGIN
FOR rec IN ( SELECT t.dia,
t.hora
FROM t_taller e,TABLE (e.dias ) t) --This is how you select records from nested table
LOOP
dbms_output.put_line(rec.dia || ' ' || rec.hora);
END LOOP;
END;
Output:
Error starting at line : 40 in command -
update t_taller set fec_fin = fec_fin + 20 where pk = 1
Error report -
ORA-04091: table SYSTM.T_TALLER is mutating, trigger/function may not see it
ORA-06512: at "SYSTM.TRG_TALLER_AU_FEC_FIN", line 2
ORA-04088: error during execution of trigger 'SYSTM.TRG_TALLER_AU_FEC_FIN'
So again you need to revisit your requirement.

Related

Compound Trigger to turn a single row into a multirow

`Basically, i need to create something that when the user insert a value on a table, it turns into a multi insert, he will say the number of rows that will become in a part of table.
But i have 0 ideia from were begin.
My table have COMPMOV - INT: is the number of rows will return.
VLRPROV - NUMBER:
DTVENC - DATE:
PRAZO - INT:
PARCELA - INT:
i started from a another trigger that i created before, but this one i just fill a field that is blank when the user insert.`
CREATE OR replace TRIGGER "TRG_INC_USU_OBSMULTI"
FOR INSERT OR UPDATE
ON AD_OBSMULTI
COMPOUND TRIGGER TYPE R_OBS_TYPE IS RECORD (
OBS_ID AD_OBSMULTI.ID%TYPE,
OBS_IDOBS AD_OBSMULTI.IDOBS%TYPE,
OBS_CODUSU AD_OBSMULTI.CODUSU%TYPE
);
TYPE T_OBS_TYPE IS TABLE OF R_OBS_TYPE INDEX BY PLS_INTEGER;
T_OBS T_OBS_TYPE;
AFTER EACH ROW IS BEGIN
T_OBS (T_OBS.COUNT + 1).OBS_IDOBS := :NEW.IDOBS;
T_OBS (T_OBS.COUNT).OBS_ID := :NEW.ID;
T_OBS (T_OBS.COUNT).OBS_CODUSU := :NEW.CODUSU;
END AFTER EACH ROW;
AFTER STATEMENT IS L_CODUSU AD_OBSMULTI.CODUSU%TYPE;
BEGIN
SELECT
STP_GET_CODUSULOGADO INTO L_CODUSU
FROM
DUAL;
FOR indx IN 1..T_OBS.COUNT
LOOP
IF T_OBS(indx).CODUSU IS NULL THEN
UPDATE
AD_OBSMULTI
SET
CODUSU = L_CODUSU
WHERE
ID = T_OBS(indx).OBS_ID
AND IDOBS = T_OBS(indx).OBS_IDOBS;
END IF;
END LOOP;
END AFTER STATEMENT;
END;
/
A trigger can modify the values of the dml statement (insert/update/delete) only. An additional transaction on the same table within a trigger on that table is generally a bad idea.
But here is a workaround.
Create a table
Create a view on that table
Create an instead of trigger on the view
Insert into the view
Example:
CREATE TABLE MAIN_TABLE (id number);
Table MAIN_TABLE created.
CREATE OR REPLACE VIEW MAIN_VIEW AS
SELECT id, 0 as new_rows FROM MAIN_TABLE;
View MAIN_VIEW created.
INSERT INTO main_view (id) values (100);
1 row inserted.
It is possible to insert into the view. Since there is a 1:1 relationship with the main_table this will insert a row in MAIN_TABLE
SELECT COUNT(*) FROM main_table;
COUNT(*)
----------
1
Now create the instead of trigger on MAIN_VIEW
CREATE OR REPLACE TRIGGER main_view_ioi
INSTEAD OF INSERT
ON main_view
FOR EACH ROW
BEGIN
FOR i IN 1 .. :NEW.NEW_ROWS LOOP
INSERT INTO main_table (id) VALUES (i);
END LOOP;
END;
/
Trigger MAIN_VIEW_IOI compiled
INSERT INTO main_view (id,new_rows) values (1,5);
1 row inserted.
Note that this will say "1 row inserted" because only 1 row was inserted in MAIN_VIEW. However, the instead of trigger created 5 rows in MAIN_TABLE.
SELECT * FROM main_table;
ID
----------
100
1
2
3
4
5

Create trigger that does the same as unique static constraint PL/SQL

As a disclaimer, this question is only for my curiosity and for practicing triggers and compound triggers particularly.
I've been trying to replace the UNIQUE constraint with a trigger in order to understand triggers more, but I haven't been successful so far, mainly because of the global variables that I'm not so comfortable with inside the compound triggers.
what I'm trying to do with a trigger :
ALTER TABLE Employee
ADD CONSTRAINT emp_UQ
UNIQUE (id_emp, id_office);
here's what I tried so far (t for type, g for global):
CREATE OR REPLACE TRIGGER BIUUniqueConstraint
FOR INSERT OR UPDATE ON Employee
COMPOUND TRIGGER
TYPE tIdEmpOffice IS TABLE OF Employee.id_emp%TYPE
INDEX BY VARCHAR2(80);
gIdEmpOffice tIdEmpOffice;
TYPE tId_emp IS TABLE OF Employee.id_emp%TYPE;
gId_emp tId_emp;
TYPE tId_office IS TABLE OF Employee.id_office%TYPE;
gId_office tId_office;
BEFORE STATEMENT IS
BEGIN
SELECT e.id_emp, e.id_office
BULK COLLECT INTO gId_emp, gId_office
FROM Employee e
ORDER BY e.id_emp;
FOR j IN 1..gId_emp.COUNT() LOOP
gIdEmpOffice(gId_emp(j)) := gId_office(j);
END LOOP;
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE(gIdEmpOffice(:NEW.id_emp);
END IF;
END BEFORE EACH ROW;
END BIUCompteParti;
/
I have no clue how to move forward with this trigger and would like suggestions and explanations if possible about how to use globale variables to store data and how to use them on a row level.
Here's one option.
Sample table:
SQL> create table employee (id_emp number, id_office number);
Table created.
Trigger:
SQL> create or replace trigger trg_emp_unique
2 for insert or update on employee
3 compound trigger
4 type t_row is record (id_emp number, id_office number);
5 type t_tab is table of t_row;
6 l_tab t_tab := t_tab();
7 l_cnt number;
8
9 before each row is
10 begin
11 l_tab.extend;
12 l_tab(l_tab.last).id_emp := :new.id_emp;
13 l_tab(l_tab.last).id_office := :new.id_office;
14 end before each row;
15
16 after statement is
17 begin
18 for i in l_tab.first .. l_tab.last loop
19 select count(*) into l_cnt
20 from employee
21 where id_emp = l_tab(i).id_emp
22 and id_office = l_tab(i).id_office;
23 if l_cnt > 1 then
24 raise_application_error(-20000, 'Unique constraint violated');
25 end if;
26 end loop;
27 l_tab.delete;
28 end after statement;
29 end trg_emp_unique;
30 /
Trigger created.
SQL>
As you can see, it doesn't contain before statement nor after each row parts; if they aren't used, you don't have to put them into the trigger.
Let's try it:
SQL> insert into employee(id_emp, id_office) values (1, 1);
1 row created.
SQL> insert into employee(id_emp, id_office) values (1, 2);
1 row created.
Re-insert the first combination (1, 1):
SQL> insert into employee(id_emp, id_office) values (1, 1);
insert into employee(id_emp, id_office) values (1, 1)
*
ERROR at line 1:
ORA-20000: Unique constraint violated
ORA-06512: at "SCOTT.TRG_EMP_UNIQUE", line 22
ORA-04088: error during execution of trigger 'SCOTT.TRG_EMP_UNIQUE'
That failed (as it should). Let's update existing rows:
SQL> select * from employee;
ID_EMP ID_OFFICE
---------- ----------
1 1
1 2
SQL> update employee set id_office = 5;
update employee set id_office = 5
*
ERROR at line 1:
ORA-20000: Unique constraint violated
ORA-06512: at "SCOTT.TRG_EMP_UNIQUE", line 22
ORA-04088: error during execution of trigger 'SCOTT.TRG_EMP_UNIQUE'
Kind of works.
You can count whether a paired value for those columns already exists with a statement level trigger such as
CREATE OR REPLACE TRIGGER trg_chk_unique_emp_dept_id
AFTER INSERT ON employee
DECLARE
val INT;
BEGIN
SELECT NVL(MAX(COUNT(*)),0)
INTO val
FROM employee
GROUP BY id_emp, id_office;
IF val > 1 THEN
RAISE_APPLICATION_ERROR(-20304,
'Each employee may be assigned to a department once at most !');
END IF;
END;
/
which will check if an attempt made to insert the same value pairs more than once, and if so, it will hurl with an error message.
Demo

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.

Oracle Trigger - ERROR: ORA-00903: invalid table name

I have a problem with my sql code.
CREATE OR REPLACE TRIGGER
BEFORE UPDATE ON TABAPPOGGIO
FOR EACH ROW
DECLARE
ERRORE EXCEPTION;
begin
IF :NEW_ConteggioPrenotazioni>150
THEN RAISE ERRORE;
END IF;
exception
when errore then raise_application_error (-20002, 'Sala Piena');
end;
I created a query before, for tabappoggio:
CREATE VIEW TABAPPOGGIO
AS
SELECT COUNT(Codice) AS ConteggioPrenotazioni
FROM PRENOTAZIONI
WHERE Sala='101'
GROUP BY Codice
But it keeps telling me ORA-00903: invalid table name.
Any help, please, or suggestions? Thanks!
EDIT: SORRY!!! I accidentally deleted a comment of someone who told me I forgot the trigger name. I saw the tick mark and clicked it but... I failed. Sorry, I still need to realize how buttons work, I am pretty new here.
ANYWAY THANK YOU!!! I literally forgot the trigger name as a fool. I didn't realize, all in panic. Thank you so much!!!
You need INSTEAD OF trigger if you want to create a trigger on view.
INSTEAD OF triggers are valid for DML events on views. They are not valid for DDL or database events.
Demo
CREATE TABLE BaseTable
(ID int PRIMARY KEY IDENTITY(1,1),
Color nvarchar(10) NOT NULL,
Material nvarchar(10) NOT NULL,
ComputedCol AS (Color + Material)
);
--Create a view that contains all columns from the base table.
CREATE VIEW InsteadView
AS SELECT ID, Color, Material, ComputedCol
FROM BaseTable;
--Create an INSTEAD OF INSERT trigger on the view.
CREATE TRIGGER InsteadTrigger on InsteadView
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO BaseTable
SELECT Color, Material
FROM inserted
END;
In your case it becomes:
CREATE OR REPLACE TRIGGER InsteadTrigger on TABAPPOGGIO
INSTEAD OF UPDATE OR INSERT
DECLARE
ERRORE EXCEPTION;
begin
IF :NEW.ConteggioPrenotazioni>150
THEN RAISE ERRORE;
END IF;
exception
when errore then raise_application_error (-20002, 'Sala Piena');
end;
Note: You can read both the :OLD and the :NEW value, but you cannot write either the :OLD or the :NEW value.
You code has some syntax issues, but the main issue is that, if I understand your need, it will not do what you expect.
If I correctly interpret you need, you want to prevent inserting more than 150 rows in a table with a given value of sala.
If so you can simply build a trigger on the table to check, performing the count after having inserted one or more rows.
For example:
create table PRENOTAZIONI( sala varchar2(10), codice number);
create or replace trigger checkPrenotazioni
after insert on prenotazioni
declare
vNum number;
ERRORE EXCEPTION;
begin
select count(codice)
into vNum
from prenotazioni
where sala = '101';
--
IF vNum >150
THEN RAISE ERRORE;
END IF;
exception
when errore
then raise_application_error (-20002, 'Sala Piena');
end;
Now I insert 150 rows with sala = '101' and everything goes well:
SQL> insert into prenotazioni(sala, codice) select '101', 101 from dual connect by level <= 150;
150 rows created.
If I try to insert the 151th row, the row is not inserted and I have:
SQL> insert into prenotazioni(sala, codice) values ('101', 101);
insert into prenotazioni(sala, codice) values ('101', 101)
*
ERROR at line 1:
ORA-20002: Sala Piena
ORA-06512: at "ALEK.CHECKPRENOTAZIONI", line 15
ORA-04088: error during execution of trigger 'ALEK.CHECKPRENOTAZIONI'
SQL> select count(1) from prenotazioni;
COUNT(1)
----------
150
SQL>
Same thing if I try to insert 151 rows in one shot:
SQL> truncate table prenotazioni;
Table truncated.
SQL> select count(1) from prenotazioni;
COUNT(1)
----------
0
SQL> insert into prenotazioni(sala, codice) select '101', 101 from dual connect by level <= 151;
insert into prenotazioni(sala, codice) select '101', 101 from dual connect by level <= 151
*
ERROR at line 1:
ORA-20002: Sala Piena
ORA-06512: at "ALEK.CHECKPRENOTAZIONI", line 15
ORA-04088: error during execution of trigger 'ALEK.CHECKPRENOTAZIONI'
It seems you are thinking too complicated. You want to restrict records in the table PRENOTAZIONI, so write an insert trigger for that table.
CREATE OR REPLACE TRIGGER trg_too_many_prenotazioni
AFTER INSERT ON prenotazioni
DECLARE
v_count INTEGER;
BEGIN
select count(*) into v_count from prenotazioni where sala = 101;
IF v_count > 150 THEN
RAISE_APPLICATION_ERROR(-20002, 'sala piena');
END IF;
END trg_too_many_prenotazioni;
(And maybe you want a SALA table with a record per sala and a column for the number of allowed prenotazioni rather then hard-coding 150 for sala = 101 here.)

Checking the date before inserting in a table ORACLE 10g

I have table:
BOOK_DT1 BOOK_DT2 USERNAME
--------- --------- --------------------
22-SEP-17 12-OCT-17 rSK
08-FEB-16 18-FEB-16 chak
05-JAN-17 12-JAN-17 rah
31-JAN-16 01-JUL-16 ABC
While inserting another column, it should check the given dates for BOOK_DT1 and BOOK_DT2 should not come into the dates present in the table.
For EX: insert into table_name('28-SEP-17','12-NOV-17','XYX'); should throw an error, because '28-SEP-17' comes in between 22-SEP-17 and 12-OCT-17.
you can achive this using the after insert trigger. Somting like this:
create or replace trigger date_check_trg
after insert
on your_table_name
v_cnt NUMBER;
begin
select count(*)
into v_cnt
from you_table_name t1
join you_table_name t2
on ( t1.BOOK_DT1 between t2.BOOK_DT1 and t2.BOOK_DT1
or t1.BOOK_DT2 between t2.BOOK_DT1 and t2.BOOK_DT1
)
AND t1.rowid != t2.rowid
;
if v_cnt > 0 then
raise_application_error(-20999, 'intersection error');
end if;
end;
/
If you want to check before the insert then BEFORE INSERT should be what you're looking for. If the name doesn't matter and your new values should not be between any values previously inserted in the table then this is how I would write it:
create or replace trigger trg_date_chk
before insert
on your_table_name for each row
declare
lnCnt NUMBER;
begin
select count(*)
into lnCnt
from you_table_name a
where :new.BOOK_DT1 < a.BOOK_DT1
and :new.BOOK_DT2 > a.BOOK_DT2;
if lnCnt > 0 then
raise_application_error(-20999, 'INSERT ERROR HERE');
end if;
end;
/

Resources