事务后运行触发器,而不是每行 - PostgreSQL 9.4

时间:2016-05-17 13:17:08

标签: postgresql

我有这个触发器来确保所有投票的总和不会超过100:

CREATE FUNCTION limit_votes() RETURNS TRIGGER AS $limit_votes$
    DECLARE
        votes_total int;
    BEGIN
        votes_total := NEW.vote + (SELECT SUM(vote) FROM cars WHERE portfolio_id = NEW.portfolio_id AND car != NEW.car);
        IF votes_total > 100 THEN
            RAISE EXCEPTION 'votes_limit_exceeded';
        END IF;
        RETURN NEW;
    END;
$limit_votes$ LANGUAGE plpgsql;
CREATE TRIGGER limit_votes BEFORE INSERT OR UPDATE ON cars FOR EACH ROW EXECUTE PROCEDURE limit_votes();

应该提到的是"投票"可以更新,所以它不仅是INSERT。 这就是我的问题发生的地方,因为一个用户可以更改汽车之间的投票,然后触发器被发出,因为单个行的更新可能超过100的限制,然后其他更新减少其他投票。

我希望它有意义。

我希望在BEGIN ... COMMIT之后调用触发器,所以我可以在检查所有内容之前更新多行 - 但是如果用户尝试更新投票,也会引发异常而不保存结果超过100。

2 个答案:

答案 0 :(得分:9)

触发器必须是约束和“后”触发器。然后你可以使用DEFERRABLE:

CREATE CONSTRAINT TRIGGER limit_votes
AFTER INSERT OR UPDATE ON cars
DEFERRABLE
FOR EACH ROW EXECUTE PROCEDURE limit_votes();

参见文档:

http://www.postgresql.org/docs/9.1/static/sql-createtrigger.html

答案 1 :(得分:0)

根据https://www.postgresql.org/docs/13/sql-createtrigger.html

由于这应该是一个延迟约束,并且您希望在事务之后触发过程执行,因此您需要以下内容,

最初推迟

CREATE CONSTRAINT TRIGGER limit_votes
AFTER INSERT OR UPDATE ON cars
DEFERRABLE
INITIALLY DEFERRED 
FOR EACH ROW EXECUTE PROCEDURE limit_votes();

最初立即

如果我们想在每个语句之后触发过程执行。

CREATE CONSTRAINT TRIGGER limit_votes
AFTER INSERT OR UPDATE ON cars
DEFERRABLE
INITIALLY IMMEDIATE 
FOR EACH ROW EXECUTE PROCEDURE limit_votes();