【问题标题】:How can I insert a row when my trigger raises an exception? [Oracle SQL]当我的触发器引发异常时,如何插入一行? [甲骨文SQL]
【发布时间】:2015-02-20 09:23:28
【问题描述】:

我正在尝试使用 APEX 制作一个名为“卡片预订”(针对学校)的项目。它应该像在电影院一样工作,有一些节目,用户可以为特别节目预订座位。

现在我想做一个触发器,验证一个房间内没有同时出现两场演出,每场演出之间应该间隔 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 相乘以获得以分钟为单位的差异,因为 a 的持续时间电影也在几分钟内。

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

当我想在没有其他节目正在运行的一天插入一个节目时,我收到“NO_DATA_FOUND”-异常,我无法插入新节目。如何插入新节目?

感谢您的帮助,抱歉英语不好:-)

【问题讨论】:

  • 嗨,如果 NO_DATA_FOUND 真的不是问题,那么您可以为 NO_DATA_FOUND 添加一个 EXCEPTIONS 子句,它会为 NULL
  • 如果电影在同一天在同一个房间放映两次(例如,在 17:00 和 20:00 放映),您也会收到过多行错误,所以你需要重新考虑如何查询数据——考虑在那个房间里的所有节目上使用光标,这样可以解决这两个错误;或计算潜在重叠的单个查询。
  • @davegreen100:谢谢,我不知道,这种方式可行:-)
  • @AlexPoole:嗯,我从来没有意识到......那个光标的代码是什么样的?

标签: sql oracle exception triggers


【解决方案1】:

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

使用此代码创建的表。您可以在 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);

测试:

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;

【讨论】:

  • 不错,谢谢;-) between 方法很好,我完全忘记了^^
  • 我注意到了一个错误。如果从 15:00 开始插入短片,16:00 结束,然后添加长片 14:00-17:00 触发器不会触发异常。添加适当的修正来处理这种情况,它的条件变化很小。
猜你喜欢
  • 2016-06-11
  • 2014-01-20
  • 2018-08-20
  • 2020-12-22
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
相关资源
最近更新 更多