如何使用 postgres 使触发器在会计软件中计算余额
Posted
技术标签:
【中文标题】如何使用 postgres 使触发器在会计软件中计算余额【英文标题】:how to cause a trigger to calculate balances in an accounting software using postgres 【发布时间】:2014-08-04 05:16:12 【问题描述】:根据我之前回答的问题,我想知道如何使用 postgres 触发器进行类似的余额计算。
how to calculate balances in an accounting software using postgres window function
ID Date In Out Balance
1 1/1 100.00 0.00 100.00
2 2/1 10.00 0.00 110.00
3 3/1 0.00 70.00 40.00
4 5/1 5.00 0.00 45.00
5 6/1 0.00 60.00 -15.00
现在我需要一个“触发器”,它会给我以下结果:
ID Date In Out Balance
1 1/1 100.00 0.00 100.00
2 2/1 10.00 0.00 110.00
3 3/1 0.00 70.00 40.00
6 4/1 20.00 0.00 60.00 <--- inserted new row
4 5/1 5.00 0.00 65.00
5 6/1 0.00 60.00 5.00
如何在 postgres 中创建触发器来更新“连续”行的余额(不更新旧行)?
【问题讨论】:
阅读this @dude ...为什么?那里有什么相关的?请详细说明。是的,这是一个“为我做”的问题,但我不确定该链接是否有用。 @CraigRinger this pdf 文件很好地解释了Triggers
并带有可以理解的例子,正如你所说的问题是 "do it for me"
这将帮助他理解触发因素,以便他可以轻松地抓住答案因为他的问题是avaialble
【参考方案1】:
这实际上比看起来更难。
可能不止一个人同时插入一行,他们的提交顺序可能与创建行的顺序不同。这意味着计算余额的触发器不会看到它应该看到的行,并且余额将是错误的。
为了使这项工作可靠,您必须在执行INSERT
之前LOCK TABLE ... IN EXCLUSIVE MODE
,或者您必须在9.2 或更高版本中使用SERIALIZABLE
隔离。两者都需要重试失败的事务:
SERIALIZABLE
将中止有问题的事务并迫使您重新尝试;和
在触发器中加锁涉及锁升级,这会导致死锁,从而导致事务中止。
因此您的应用必须准备好重试失败的事务。
为避免这种情况,您可以使用READ COMMITTED
隔离,并让应用程序明确地LOCK TABLE ... IN EXCLUSIVE MODE
感兴趣的表之前它会尝试用它做任何其他事情,甚至是SELECT
,如果它认为它可能稍后需要INSERT
一行进入它。但是,并发性会有些糟糕。
因此,鉴于此,您可以编写如下内容:
CREATE OR REPLACE FUNCTION balance_insert_trigger()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
-- This can deadlock unless you already took the lock earlier
-- in the transaction; we put it here only for safety to make
-- sure to block concurrent inserts.
LOCK TABLE mytable IN EXCLUSIVE MODE;
IF tg_op = 'INSERT' THEN
NEW.balance = (SELECT sum(in) - sum(out) FROM mytable);
RETURN NEW
ELSE
-- It's not safe to DELETE FROM or UPDATE this table because of the
-- running balance.
RAISE EXCEPTION '% operation not permitted on this table', tg_op;
END IF;
END;
$$;
CREATE TRIGGER balance_insert_trigger
BEFORE INSERT OR UPDATE OR DELETE ON mytable
FOR EACH ROW EXECUTE PROCEDURE balance_insert_trigger();
那么总是:
BEGIN;
LOCK TABLE mytable IN EXCLUSIVE MODE;
INSERT INTO mytable ...;
COMMIT;
如果你也想支持UPDATE
和DELETE
,那么事情就会变得令人兴奋。
【讨论】:
哇,看起来很精致。只需先在 Answared 中标记,然后再尝试。非常感谢你们。以上是关于如何使用 postgres 使触发器在会计软件中计算余额的主要内容,如果未能解决你的问题,请参考以下文章
如何创建一个 Postgres 11 触发器函数,该函数在插入或更新到表“a”时在表“b”中插入一个新行?