当触发器引发异常时,如何插入行?[Oracle SQL]

当触发器引发异常时,如何插入行?[Oracle SQL],sql,oracle,exception,triggers,Sql,Oracle,Exception,Triggers,我正试图做一个项目,这是名为“卡预订”(学校)与顶点。它应该像在电影院一样工作,有几个节目,用户可以为一个特殊的节目预订座位 现在我想做一个触发器,谁来验证一个房间里不会同时有两个节目,每个节目之间的间隔应该是15分钟 现在看起来是这样的: create or replace trigger tg_roomoccupancy before insert or update on show for each row declare sDate date; sDuration number(

我正试图做一个项目,这是名为“卡预订”(学校)与顶点。它应该像在电影院一样工作,有几个节目,用户可以为一个特殊的节目预订座位

现在我想做一个触发器,谁来验证一个房间里不会同时有两个节目,每个节目之间的间隔应该是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;+
创建或替换触发器tg\u
在显示时插入或更新之前
每行
声明
日期;
持续时间(4);
新时长数(4);
开始
从show where room=:new.room和to_char(datum,'DD-MM-YYYY')=to_char(:new.datum,'DD-MM-YYYY')中选择datum into sDate;
从胶片f中选择dauer into vDuration,显示s在何处显示字符(datum,'DD-MM-YYYY')=到字符(:new.datum,'DD-MM-YYYY'),s.filmId=f.filmId;
从film中选择dauer to newDuration,其中film.filmId=:new.filmId;
如果(((:new.datum-sDate)*1440)<(sDuration+15))和((:new.datum-vDate)*1440)>0),则
raise_应用程序_错误(-20001,“这个房间里还有其他节目!”);
elsif(((sDate-:new.datum)*1440)<(newDuration+15))和((sDate-:new.datum)*1440)>0)然后
raise_应用程序_错误(-20002,'节目持续时间太长,另一个节目将开始!');
elsif((sDate-:new.datum)=0)然后
raise_应用程序_错误(-20003,'两个节目不能同时启动!');
如果结束;
结束+
你可以看到,ifs在做什么,我乘以1440,因为两个日期之间的减法得到一个以天为单位的数字,我把它乘以*24*60,得到以分钟为单位的差值,因为电影的持续时间也是以分钟为单位的

触发器会根据我的需要引发错误,但我的问题是:

当我想在没有其他节目运行的日子插入一个节目时,我会得到一个“no_DATA_FOUND”异常,我无法插入新的节目。如何插入新节目


感谢您的帮助,并为糟糕的英语感到抱歉:-)

您可以在下面的触发器中应用类似于此的逻辑

使用此代码创建的表。您可以在show.filmId检查电影表中是否存在电影时添加约束, 但在这里它是由触发器完成的。我还会将两个错误(2002和2003)合并为一个并抛出错误 “这间屋子里有另一场演出,或者间隔太短”,但这取决于你

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);
测试:

触发代码:

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;

嗨,如果找不到任何数据真的不是问题,那么你可以为找不到任何数据添加一个例外条款,它不会为空。如果电影在同一天在同一房间放映两次(比如17:00和20:00),你也会得到太多的行错误,因此,你需要重新思考你是如何查询数据的——考虑在该房间的所有显示中使用光标,这将解决这两个错误;或者一个计算潜在重叠的查询。@davegreen100:谢谢你,我不知道,这种方法是有效的:-)@AlexPoole:嗯,我从来没有意识到。。。光标的代码是什么样子的?很好,谢谢;-)between方法很好,我完全忘记了^^我注意到一个bug。如果插入15:00开始、16:00结束的短电影,然后添加14:00-17:00的长电影,触发器将不会触发异常。添加适当的修正以应对这种情况,这是一个很小的条件变化。
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;