Une instruction d'insertion peut insérer plusieurs lignes. Ex. :
insert into booking(booking_start, booking_end, booking_room, guest_no)
select date '2019-11-01', date '2019-11-10', 4, 10 from dual
union all
select date '2019-11-08', date '2019-11-15', 4, 88 from dual;
Ces insertions se produisent dans un ordre arbitraire, vous ne pouvez donc pas vraiment accepter une ligne et pas l'autre. Au lieu de cela, vous devez rejeter l'intégralité de l'instruction insert. Il en va de même pour les mises à jour bien sûr, si cela peut être fait.
En conséquence, vous écririez un déclencheur d'instruction après où vous examineriez la nouvelle situation dans le tableau.
CREATE OR REPLACE TRIGGER trg_reject_invalid_bookings
AFTER INSERT OR UPDATE ON booking
DECLARE
v_count INTEGER;
BEGIN
SELECT count(*)
INTO v_count
FROM booking b1
WHERE EXISTS
(
SELECT *
FROM booking b2
WHERE b2.booking_id <> b1.booking_id
AND b2.booking_room = b1.booking_room
AND b2.booking_start < b1.booking_end
AND b2.booking_end > b1.booking_start
)
AND rownum = 1; -- it suffices to find one overlapping pair
IF v_count > 0 THEN
raise_application_error(-20000, 'Invalid booking');
END IF;
END trg_reject_invalid_bookings;
Si la table est volumineuse et que vous souhaitez uniquement consulter les lignes insérées/mises à jour afin que ce déclencheur s'exécute rapidement, vous devez écrire un déclencheur composé à la place, dans lequel vous vous souvenez de la réservation des ID dans un tableau au niveau de la ligne et ne regardez que ces lignes au niveau de l'instruction.