我有一个
posts(id, likes)
表(likes = number of likes for that post)
和
post_likes(post_id, user_id)
表(the users who liked a post)
。
我有一个触发器(post_likes_after_insert)
所以当我添加新的时候会增加posts.likes
和另一个减少(post_likes_before_delete)
的触发器posts.likes
。一切正常。
然后我为帖子添加了另一个触发器(before delete)
,以删除post_likes
,但这会触发上面的触发器,从而减少posts.likes
列。
所以它给了我这个错误:
表帖子正在变异,触发器/功能可能无法看到它 post_likes_before_delete ,第4行;执行触发器时出错 post_likes_before_delete
这是一个带有代码的pastebin,底部是完整的错误。 http://pastebin.com/EQHTLZFp
感谢。
-----------------------------------------------------------------------
-- USERS
-----------------------------------------------------------------------
CREATE TABLE users
(
id NUMBER(10) PRIMARY KEY NOT NULL,
email CHAR(100) UNIQUE NOT NULL,
password CHAR(60) NOT NULL,
first_name CHAR(30) NOT NULL,
last_name CHAR(30) NOT NULL,
birth_date DATE NULL,
gender CHAR(10) NULL,
joined TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT gender_check CHECK (UPPER(gender) IN ('M', 'F'))
);
-- Auto increment for users.id
DROP SEQUENCE users_sequence;
CREATE SEQUENCE users_sequence START WITH 1 INCREMENT BY 1;
CREATE TRIGGER users_before_insert
BEFORE INSERT
ON users REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT users_sequence.nextval INTO :NEW.ID FROM dual;
END;
/
--
-- POSTS
--
CREATE TABLE posts
(
id NUMBER(10) PRIMARY KEY NOT NULL,
user_id NUMBER(10) REFERENCES users(id) NOT NULL,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
content char(1000) NOT NULL,
likes NUMBER(10) DEFAULT 0 NOT NULL,
privacy CHAR(10) DEFAULT 'public' NOT NULL,
CONSTRAINT fk_posts FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Auto increment for posts.id
DROP SEQUENCE posts_sequence;
CREATE SEQUENCE posts_sequence START WITH 1 INCREMENT BY 1;
CREATE TRIGGER posts_before_insert
BEFORE INSERT
ON posts REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT posts_sequence.nextval INTO :NEW.ID FROM dual;
END;
/
CREATE TRIGGER posts_before_delete
BEFORE DELETE
ON posts
FOR EACH ROW
BEGIN
DELETE FROM post_likes WHERE post_id = :old.id;
END;
/
--
-- POST_LIKES
--
CREATE TABLE post_likes
(
user_id NUMBER(10) NOT NULL REFERENCES users(id),
post_id NUMBER(10) NOT NULL REFERENCES posts(id),
PRIMARY KEY (user_id, post_id),
--CONSTRAINT fk_post_likes1 FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
CONSTRAINT fk_post_likes2 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Increments posts.likes
CREATE TRIGGER post_likes_after_insert
AFTER INSERT
ON post_likes
FOR EACH ROW
DECLARE
n NUMBER(10);
BEGIN
SELECT likes INTO n FROM posts WHERE id = :new.post_id;
UPDATE posts SET likes = n+1 WHERE id = :new.post_id;
END;
/
-- Decrements posts.likes
CREATE TRIGGER post_likes_before_delete
BEFORE DELETE
ON post_likes
FOR EACH ROW
DECLARE
n NUMBER(10);
BEGIN
SELECT likes INTO n FROM posts WHERE id = :old.post_id;
UPDATE posts SET likes = n-1 WHERE id = :old.post_id;
END;
/
-- Full error, EUSEBIU is the username that I'm logged in
-- ERROR at line 1:
-- ORA-04091: table EUSEBIU.POSTS is mutating, trigger/function may not see it
-- ORA-06512: at "EUSEBIU.POST_LIKES_BEFORE_DELETE", line 4
-- ORA-04088: error during execution of trigger 'EUSEBIU.POST_LIKES_BEFORE_DELETE'
-- ORA-06512: at "EUSEBIU.POSTS_BEFORE_DELETE", line 2
-- ORA-04088: error during execution of trigger 'EUSEBIU.POSTS_BEFORE_DELETE'
答案 0 :(得分:0)
看看如果删除帖子会发生什么。您的触发器尝试删除post_likes。这就是为什么你的另一个触发器试图按你的意愿减少posts.likes。所以,你试图做出不必要的行动并看到变异,因为在帖子上删除会导致帖子更新。
你应该做的就是打破这个链条。你完全删除帖子时不应该尝试改变喜欢。例如,您可以使用类似
的内容create or replace trigger MY_BEFORE_DELETE_LIKE_TRIGGER ...
begin
-- Let's do nothing if deleting master too
if dbms_utility.format_call_stack like '%MY_BEFORE_DELETE_POSTS_TRIGGER%' then
return;
end if;
...
更正确的方法是将flag用于打包变量或类似的东西。