当我的触发器引发异常时如何插入一行? [甲骨文SQL]
How can I insert a row when my trigger raises an exception? [Oracle SQL]
我正在尝试使用 APEX 创建一个名为 "cards reservation"(针对学校)的项目。它应该像在电影院一样工作,有一些节目,用户可以为特别节目预订座位。
现在我想做一个触发器,验证在一个房间里没有同时有 2 个节目并且每个节目之间应该是 15 分钟。
目前看起来是这样的:
create or replace trigger tg_roomoccupancy
before insert or update on show
for each row
declare
sDate date;
sDuration number(4);
newDuration number(4);
begin
select datum into sDate from show where room = :new.room and to_char(datum, 'DD-MM-YYYY') = to_char(:new.datum, 'DD-MM-YYYY');
select dauer into vDuration from film f, show s where to_char(datum, 'DD-MM-YYYY') = to_char(:new.datum, 'DD-MM-YYYY') AND s.filmId = f.filmId;
select dauer into newDuration from film where film.filmId = :new.filmId;
if((((:new.datum - sDate)*1440) < (sDuration + 15)) AND (((:new.datum - vDate)*1440) > 0))then
raise_application_error(-20001, 'There is an other show running in this room!');
elsif((((sDate - :new.datum)*1440) < (newDuration + 15)) AND ((sDate - :new.datum)*1440) > 0) then
raise_application_error(-20002, 'The show lasts too long, an other show will start!');
elsif((sDate - :new.datum) = 0) then
raise_application_error(-20003, 'Two shows cannot start at the same time!');
end if;
end;+
你可以看到,ifs 在做什么,我乘以 1440,因为两个日期之间的减法给出了一个以天为单位的数字,我将其乘以 *24*60 以获得以分钟为单位的差异,因为持续时间一部电影的时间也以分钟为单位。
触发器引发了我想要的错误,但我的问题是:
当我想在没有其他节目 运行 的一天插入一个节目时,我得到一个 "NO_DATA_FOUND"-Exception,我无法插入新节目。如何插入新节目?
感谢您的帮助,抱歉英语不好:-)
您可以在下面的触发器中应用与此类似的逻辑。
使用此代码创建的表。您可以添加约束 show.filmId 检查电影 table 中是否存在电影,
但这里是通过触发器完成的。我还将两个错误(2002 和 2003)合并为一个并抛出错误
"Another show running in this room or interval too short",但这取决于你。
create table show (datum date not null, room number not null, filmId number not null);
create table film (filmId number not null unique, dauer number not null);
insert into film values (1, 120);
测试:
insert into show (datum, room, filmId) values
(to_date('2015-01-01 15:00:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> OK
insert into show (datum, room, filmId) values
(to_date('2015-01-01 15:00:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 2);
=> Incorrect movie ID.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 16:00:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> Another show running in this room.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 17:10:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> Interval between shows too short.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 17:20:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> OK.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 17:20:00', 'yyyy-MM-dd HH24:mi:ss'), 2, 1);
=> OK. (Show is in another room.)
触发代码:
create or replace trigger tg_roomoccupancy
before insert or update on show
for each row
declare
v_duration number;
v_cnt number;
begin
begin
select dauer into v_duration
from film f where filmId = :new.filmId;
exception when no_data_found then
raise_application_error(-20001, 'Incorrect movie ID.');
end;
select count(1) into v_cnt from show join film f using (filmId)
where room = :new.room and
((:new.datum between datum and datum + f.dauer/1440)
or (:new.datum+v_duration/1440 between datum and datum + f.dauer/1440));
if v_cnt > 0 then
raise_application_error(-20002, 'Another show running in this room.');
end if;
select count(1) into v_cnt from show join film f using (filmId)
where room = :new.room and
((:new.datum between datum - 15/1440 and datum + (f.dauer + 15)/1440)
or (:new.datum + v_duration/1440
between datum - 15/1440 and datum + (f.dauer+15)/1440));
if v_cnt > 0 then
raise_application_error(-20003, 'Interval between shows too short.');
end if;
end;
我正在尝试使用 APEX 创建一个名为 "cards reservation"(针对学校)的项目。它应该像在电影院一样工作,有一些节目,用户可以为特别节目预订座位。
现在我想做一个触发器,验证在一个房间里没有同时有 2 个节目并且每个节目之间应该是 15 分钟。
目前看起来是这样的:
create or replace trigger tg_roomoccupancy
before insert or update on show
for each row
declare
sDate date;
sDuration number(4);
newDuration number(4);
begin
select datum into sDate from show where room = :new.room and to_char(datum, 'DD-MM-YYYY') = to_char(:new.datum, 'DD-MM-YYYY');
select dauer into vDuration from film f, show s where to_char(datum, 'DD-MM-YYYY') = to_char(:new.datum, 'DD-MM-YYYY') AND s.filmId = f.filmId;
select dauer into newDuration from film where film.filmId = :new.filmId;
if((((:new.datum - sDate)*1440) < (sDuration + 15)) AND (((:new.datum - vDate)*1440) > 0))then
raise_application_error(-20001, 'There is an other show running in this room!');
elsif((((sDate - :new.datum)*1440) < (newDuration + 15)) AND ((sDate - :new.datum)*1440) > 0) then
raise_application_error(-20002, 'The show lasts too long, an other show will start!');
elsif((sDate - :new.datum) = 0) then
raise_application_error(-20003, 'Two shows cannot start at the same time!');
end if;
end;+
你可以看到,ifs 在做什么,我乘以 1440,因为两个日期之间的减法给出了一个以天为单位的数字,我将其乘以 *24*60 以获得以分钟为单位的差异,因为持续时间一部电影的时间也以分钟为单位。
触发器引发了我想要的错误,但我的问题是:
当我想在没有其他节目 运行 的一天插入一个节目时,我得到一个 "NO_DATA_FOUND"-Exception,我无法插入新节目。如何插入新节目?
感谢您的帮助,抱歉英语不好:-)
您可以在下面的触发器中应用与此类似的逻辑。
使用此代码创建的表。您可以添加约束 show.filmId 检查电影 table 中是否存在电影, 但这里是通过触发器完成的。我还将两个错误(2002 和 2003)合并为一个并抛出错误 "Another show running in this room or interval too short",但这取决于你。
create table show (datum date not null, room number not null, filmId number not null);
create table film (filmId number not null unique, dauer number not null);
insert into film values (1, 120);
测试:
insert into show (datum, room, filmId) values
(to_date('2015-01-01 15:00:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> OK
insert into show (datum, room, filmId) values
(to_date('2015-01-01 15:00:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 2);
=> Incorrect movie ID.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 16:00:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> Another show running in this room.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 17:10:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> Interval between shows too short.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 17:20:00', 'yyyy-MM-dd HH24:mi:ss'), 1, 1);
=> OK.
insert into show (datum, room, filmId) values
(to_date('2015-01-01 17:20:00', 'yyyy-MM-dd HH24:mi:ss'), 2, 1);
=> OK. (Show is in another room.)
触发代码:
create or replace trigger tg_roomoccupancy
before insert or update on show
for each row
declare
v_duration number;
v_cnt number;
begin
begin
select dauer into v_duration
from film f where filmId = :new.filmId;
exception when no_data_found then
raise_application_error(-20001, 'Incorrect movie ID.');
end;
select count(1) into v_cnt from show join film f using (filmId)
where room = :new.room and
((:new.datum between datum and datum + f.dauer/1440)
or (:new.datum+v_duration/1440 between datum and datum + f.dauer/1440));
if v_cnt > 0 then
raise_application_error(-20002, 'Another show running in this room.');
end if;
select count(1) into v_cnt from show join film f using (filmId)
where room = :new.room and
((:new.datum between datum - 15/1440 and datum + (f.dauer + 15)/1440)
or (:new.datum + v_duration/1440
between datum - 15/1440 and datum + (f.dauer+15)/1440));
if v_cnt > 0 then
raise_application_error(-20003, 'Interval between shows too short.');
end if;
end;