PLSQL 中的触发器问题

Posted

技术标签:

【中文标题】PLSQL 中的触发器问题【英文标题】:Trigger problems in PLSQL 【发布时间】:2014-03-08 20:56:13 【问题描述】:

我一直在尝试获得一个基本上会运行这样的约束的触发器; 约束(日期

它将一个表格(比赛)中的日期与另一表格(会议)中的日期进行比较。我知道我可以使用外键来实现这一点,但我很确定会获得更多我需要使用触发器的标记。

到目前为止,我得到了这个:

CREATE OR REPLACE TRIGGER race_date_trg    
AFTER INSERT OR UPDATE
  ON RACE
  FOR EACH ROW
  DECLARE
    MEETING_ENDDATE DATE;
    STARTDATE race.racedate%TYPE;
  BEGIN
    SELECT ENDDATE INTO MEETING_ENDDATE FROM meeting;
    IF STARTDATE > MEETING_ENDDATE THEN
      RAISE_APPLICATION_ERROR(-20000, 'Wrong start date!');
    END IF;
  end race_date_trg;

它编译得很好,但是当我尝试用会引发错误的东西填充我的表时,我得到了这个:

Error report:
SQL Error: ORA-04091: table SE488.MEETING is mutating, trigger/function may not see it
ORA-06512: at "SE488.RACE_DATE_TRG", line 5
ORA-04088: error during execution of trigger 'SE488.RACE_DATE_TRG'
04091. 00000 -  "table %s.%s is mutating, trigger/function may not see it"
*Cause:    A trigger (or a user defined plsql function that is referenced in
           this statement) attempted to look at (or modify) a table that was
           in the middle of being modified by the statement which fired it.
*Action:   Rewrite the trigger (or function) so it does not read that table.

感谢您的帮助。

创建表格:

CREATE TABLE Meeting
(
MeetLocation varchar2(60),
StartDate date,
EndDate date,
MeetName varchar2(60)
);

CREATE TABLE Race
(
RaceID NUMBER,
RaceLocation varchar2(60),
MeetingStart date,
RaceDate date,
RaceTime timestamp(0), 
RaceName varchar2(60),
RaceType varchar2(8),
MinAge numeric(2),
MaxAge numeric(2),
Sex varchar2(2) NULL
);

填充它们:

  INTO Meeting (MeetLocation,StartDate,EndDate,MeetName)
    values('Talbot','30-Jul-05','07-Aug-05','Midlands Derby')
  INTO Meeting (MeetLocation,StartDate,EndDate,MeetName)
    values('Ascot','04-Jul-10','07-Aug-10','National Derby')

  INTO Race (RaceID,RaceLocation,MeetingStart,RaceDate,RaceTime,RaceName,RaceType,MinAge,MaxAge,Sex)
    values('1','Talbot','20-Jul-05','31-Jul-05',to_date('2005/07/31:12:00:00PM', 'yyyy/mm/dd:hh:mi:sspm'),'600m Dash','Flat','2','10','M')
  INTO Race (RaceID,RaceLocation,MeetingStart,RaceDate,RaceTime,RaceName,RaceType,MinAge,MaxAge,Sex)
    values('2','Talbot','30-Jul-05','01-Aug-05',to_date('2005/08/01:01:10:00PM', 'yyyy/mm/dd:hh:mi:sspm'),'1km Hurdles','Flat','6','12','F')

【问题讨论】:

race 上的INSERTUPDATE 是否来自MEETING 表上定义的另一个触发器? Mihai,我在使用 BEFORE 时也遇到了同样的错误。 @JustinCave,我不这么认为 - 这是我唯一的触发器。 发布一个可重现的测试用例。发布 DDL 以创建两个表。如果需要该数据来重现问题,请发布 DML 以填充表。发布您正在使用的导致触发器触发的语句。 @Naffel - 缺少一些东西,您提供的代码不会给出该错误。查询user_triggers 和/或user_objects,看看是否有你忘记的东西。也许是您为之前的尝试创建的触发器? “我很肯定会得到更多我需要使用触发器的分数” 做出糟糕的设计决定的可怕原因。触发器很少是正确的实现。 【参考方案1】:
CREATE OR REPLACE TRIGGER race_date_trg
BEFORE INSERT OR UPDATE ON RACE
FOR EACH ROW
DECLARE
    meet_date date;
    start_date date := :new.RaceDate;
BEGIN
    SELECT StartDate INTO meet_date FROM meeting WHERE MeetLocation = :new.RaceLocation;
    IF start_date > meet_date THEN
        RAISE_APPLICATION_ERROR(-20000, 'Wrong start date!');
    END IF;
END race_date_trg;
/

我认为您想要引发错误或异常。当有人插入或更新餐桌比赛时,如果开始日期(来自餐桌比赛)低于开会日期(来自餐桌会议)。 :D

【讨论】:

我仍然遇到同样的错误,即使数据不应该出现错误。 :// 您是否删除了旧触发器?您必须先删除旧触发器。 :D

以上是关于PLSQL 中的触发器问题的主要内容,如果未能解决你的问题,请参考以下文章

PLSQL 触发器 ORA 01403 未找到数据

每行设置 new.column 的 PLSQL 触发器不起作用

如果 Column_X 更新,PLSQL 触发器记录对审计表的更新

PLSQL:触发器的语法问题

PLSQL 触发器:插入前

限制列char触发器plsql