当我尝试向表中插入值时,触发器不起作用

时间:2019-05-07 07:36:49

标签: oracle plsql

我正在尝试为名为Marks的表创建一个插入触发器,该表具有id,id_student,id_course,值,data_notation,created_at,updated_at。

我需要对旧值进行更新,如果要插入的值高于列中已经存在的值,并且如果列中没有值,则可以使用新值进行插入。

我创建了触发器,并且没有编译错误。

CREATE OR REPLACE TRIGGER insert_value
before INSERT ON Marks
FOR EACH ROW

BEGIN

   IF (:OLD.value IS NULL) THEN 
     DBMS_OUTPUT.PUT_LINE('Inserting.. because value is null');
     UPDATE Marks SET value = :NEW.value where id_student = :NEW.id_student;

   ELSE 
     DBMS_OUTPUT.PUT_LINE('Updating old value.. if old value is smaller than the one we want');

     IF (:OLD.value < :NEW.value) THEN
       UPDATE Marks SET value = :NEW.value where :OLD.id_student = :NEW.id_student;
     END IF;  
   END IF;

END;

我想针对特定ID将旧值从现有值5更改为null。

update Marks set value = null where id = 692;
select * from Marks where id = 692;

但是当我试图在表中插入一个值时,我可以通过触发器将null值更改为6

INSERT INTO Marks
VALUES (692, 43, 12, 6,  '13-02-2018', '13-02-2018', '13-02-2018');

我收到一个错误。

Error report -
SQL Error: ORA-00001: unique constraint (STUDENT.SYS_C007784) violated
00001. 00000 -  "unique constraint (%s.%s) violated"
*Cause:    An UPDATE or INSERT statement attempted to insert a duplicate key.
           For Trusted Oracle configured in DBMS MAC mode, you may see
           this message if a duplicate entry exists at a different level.
*Action:   Either remove the unique restriction or do not insert the key.

它打印一次:

Inserting.. because value is null

但是当我尝试检查触发器是否完成其工作时,请使用:

SELECT * from Marks where id = 692;

它不会更新任何内容。

它必须是由插入操作触发的触发器。因此,我无法将插入内容插入表中,但是我应该怎么写才能使其正常工作呢?

2 个答案:

答案 0 :(得分:1)

您的问题来自由于插入而递归调用触发器。以下将工作。它不捕获update语句。它只关心插入。如果该行已存在,则该行将首先被删除,并且如果现有值较高,则将现有值用于插入。

set lin 20000
drop table marks;

create table Marks(
  id          number,
  id_student  number,
  id_course   number,
  value       number,
  data_notation varchar2(40), 
  created_at  timestamp,
  updated_at  timestamp,
  CONSTRAINT marks#u UNIQUE (id, id_student, id_course)
  );

create or replace trigger mark_trigger
before insert on marks
for each row
declare
  l_value number;
  l_data_notation varchar2(40);
  l_created_at timestamp;
begin
  select value, data_notation, created_at
  into   l_value, l_data_notation, l_created_at
  from
  (select *
  from   marks
  where  marks.id   = :new.id
    and  marks.id_student = :new.id_student 
    and  marks.id_course  = :new.id_course
  order by created_at desc)    
    where  rownum=1;
  if l_value is null then
    return;
  end if;
  if l_value > :new.value then
    :new.value := l_value;
    :new.data_notation := l_data_notation; 
    :new.created_at := l_created_at;
  else
    :new.updated_at := systimestamp;
  end if;
  delete from marks 
  where marks.id  = :new.id
  and  id_student = :new.id_student 
  and  id_course  = :new.id_course;
exception
  when no_data_found then
    null;
end;  


create or replace procedure marks_insert(
  i_id          number,
  i_id_student  number,
  i_id_course   number,
  i_value       number,
  i_data_notation varchar2
)
is
begin
   INSERT INTO marks
        VALUES (i_id, i_id_student, i_id_course, i_value, i_data_notation, systimestamp, null);
END marks_insert;

begin
  delete from marks;
  marks_insert(1,1,1,5,'1 first entry');
  marks_insert(1,1,1,6,'1 second entry');
  marks_insert(1,1,2,3,'2 first entry');
  marks_insert(1,1,2,2,'2 second entry');
end;

select * from marks;

输出:

Table dropped.
Table created.
Trigger created.
Procedure created.
 PL/SQL procedure successfully completed.

        ID ID_STUDENT  ID_COURSE      VALUE DATA_NOTATION                            CREATED_AT                                         UPDATED_AT                                        
---------- ---------- ---------- ---------- ---------------------------------------- -------------------------------------------------- --------------------------------------------------
         1          1          1          6 1 second entry                           07/05/2019 13:31:31.266817                         07/05/2019 13:31:31.266928                        
         1          1          2          3 2 first entry                            07/05/2019 13:31:31.268032                                                                           

2 rows selected.

答案 1 :(得分:0)

以递归方式插入标记(插入之前在触发器中的insert语句)时将插入标记,依此类推。因此是错误的直接原因。