我有三张桌子,电影,表演和房间。我想在一个给定的房间里为一部电影插入新的节目,我想如果没有时间与现有的电影发生冲突,我可以用一个触发器来实现它。
我写了这个:
CREATE OR REPLACE TRIGGER insert_new_show
BEFORE INSERT ON show
FOR EACH ROW
DECLARE
-- pragma autonomous_transaction;
collisioni varchar(40);
runtime INT;
error1 EXCEPTION;
error2 EXCEPTION;
BEGIN
IF :new.time < CURRENT_TIMESTAMP THEN
RAISE error1;
END IF;
SELECT runtime INTO runtime
FROM film
WHERE title = deref(:new.di_film).title;
SELECT film.title INTO collisioni
FROM show JOIN film ON deref(show.di_film).title=film.title
WHERE DEREF(room).nome = DEREF(:NEW.room).nome
AND ( (:new.time < show.time AND :new.time + runtime + 10 > show.time)
OR (:new.time > show.time
AND :new.time < show.time + runtime + 10));
IF NOT SQL%NOTFOUND THEN
INSERT INTO show
SELECT to_timestamp(:NEW.orario,'yyyy-mm-dd hh24:mi:ss')
, :NEW.max_n_spot,:NEW.costo, REF(s), NULL, REF(f)
FROM film f, room s
WHERE f.title=deref(:NEW.di_film).title
AND s.nome=deref(:NEW.room).nome;
ELSE
RAISE error2;
END IF;
EXCEPTION
WHEN error1 THEN
RAISE_APPLICATION_ERROR(-20491,'Error');
WHEN error2 THEN
RAISE_APPLICATION_ERROR(-20491,'Error');
END;
如果我不使用“pragma autonomous_transaction”,则会出现table s%s is mutating
错误。但是,当然,对于事务,触发器无法看到:new
值。
我还想用CHECK CONSTRAINT进行检查,但我不知道它是否有效。
你能帮我找一个解决方案吗?
答案 0 :(得分:0)
这是经典的“使用包/程序”的情况。
当您在当前正在执行DML操作的触发器中查询表时,会得到ORA-04091: table name is mutating, trigger/function may not see it
。 Oracle不允许这样做以保持数据的读取一致性视图有多种方法可以避免这种情况,其中大多数都涉及尝试做一些稍微有点时髦的事情;包括你已经注意到自主交易。
但是,它们不会影响错误的根本原因;也就是说,你做错了什么。此错误通常表示两件事中的一件或两件:
解决方案是将逻辑移动到包或过程,这具有删除模糊层和帮助调试的额外好处。
我无法看到如何在这里检查约束,因为您仍然需要知道FILM的运行时,这需要查询第二个表。