我正在尝试为名为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;
它不会更新任何内容。
它必须是由插入操作触发的触发器。因此,我无法将插入内容插入表中,但是我应该怎么写才能使其正常工作呢?
答案 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语句)时将插入标记,依此类推。因此是错误的直接原因。