【问题标题】:Create function in Postgresql that inserts data into the table row thats been updated在 Postgresql 中创建函数,将数据插入到已更新的表行中
【发布时间】:2016-01-17 17:34:51
【问题描述】:

我一直试图弄清楚如何创建一个触发器/函数,该触发器/函数将在更新表行时计算一个值。这是我正在创建的 DVD 出租数据库。我有一些数据库经验,但我才开始使用触发器和函数。我想要发生的是,当员工插入电影归还日期时,它将采用租借日期并将其从归还日期中减去,然后将天差乘以每天 1.99 美元的租金成本。我有计算它的表达式。我想要一个触发器来运行表达式并将结果插入到该表中。

例如:

客户返回电影,员工在 Rent 表中输入返回日期,当更新此行时,触发器将运行一个计算欠款金额的表达式,并将结果插入到 Rent 表行中的 amount_owed 列。

这是我一直在尝试的一些事情,触发器执行了该函数,但之后我得到了一个错误。

功能代码:

CREATE OR REPLACE FUNCTION update_cus_balance(integer)
  RETURNS void AS
$BODY$
BEGIN

UPDATE rent
SET amount_owed=subquery.balance

FROM (SELECT date_part('day'::text, rent.return_date - rent.rent_date) *         2.99::double precision AS balance

from rent) AS subquery
WHERE rent.rent_id=rent_id;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION update_cus_balance(integer)
  OWNER TO postgres;

触发代码:

CREATE TRIGGER update_balance
AFTER UPDATE
ON rent
FOR EACH ROW
EXECUTE PROCEDURE amount_owed();

当我尝试添加 return_date 并保存更改时,PGadmin III 只会说“发生错误”。

【问题讨论】:

  • DVD 出租?多么古朴。我确实注意到您正在调用一个名为 amount_owed() 的东西,但定义了一个名为 update_cus_balance() 的东西。
  • 错误是什么?可能调用了一个不存在的函数?另外,您确定要插入一个新行,而不是实际更新现有行吗?
  • 我会用我得到的错误更新我的帖子。函数和触发器都正确插入。只是当我用返回日期更新一行时,我收到一个错误。是的,我相信我想更新一行而不是插入一行。我不确定如何在更新查询中正确使用我的表达式。我们在一个小镇的便利店经营一家小型 DVD 出租店。所以我们仍然得到了很好的生意。感谢您迄今为止的帮助。
  • amount_owed 列是我希望表达式结果更新的位置。 update_cus_balance 是我创建的一个函数。
  • 好的,我去日志,当我尝试更新一行时发现了这个错误。 “超出堆栈深度限制”。

标签: database postgresql


【解决方案1】:

就像 Jakub 指出的那样,您需要一个 BEFORE UPDATE 触发器来完成这项工作。这样的触发器有两个重要特征:

  1. 您有一个OLD 和一个NEW 变量,它们保存更新前行的值以及更新后的样子。您可以操作 NEW 变量,然后将这些更改保存到表中。
  2. 如果某些更改不合适,您可以中止整个更新。

对于您的情况,触发器函数看起来有点像这样:

CREATE OR REPLACE FUNCTION update_cus_balance(integer)
  RETURNS void trigger AS -- A trigger function should ALWAYS return trigger
$BODY$
BEGIN
  -- Calculate rent if the return date is set or changed
  IF NEW.return_date <> OLD.return_date THEN 
    IF NEW.return_date = NEW.rent_date THEN -- Same day returns
      NEW.amount_owed := 2.99;
    ELSE
      NEW.amount_owed := (NEW.return_date - NEW.rent_date) * 2.99;
    END IF;
  END IF;

  -- Trigger function should ALWAYS return NEW to succeed.
  -- Return NULL to make the update fail.
  RETURN NEW; 
END
$BODY$ LANGUAGE plpgsql;

触发器应该是:

CREATE TRIGGER update_balance
BEFORE UPDATE ON rent
FOR EACH ROW EXECUTE PROCEDURE update_cus_balance();

请注意,我假设 rent_date 和 return_date 的类型为 date(顾名思义)。如果它们是 timestamps,您可以创建两个变量和 EXTRACT() 租赁日期并返回到这些变量中。

PostgreSQL 中的触发器和函数不是很复杂,但请仔细阅读excellent manual。

【讨论】:

    【解决方案2】:

    rent 表上的 update 会触发 trigger,触发器会更新租用表。租金表上的更新触发了一个触发器,一个触发器......

    这就是您收到stack depth limit exceeded 错误的原因。

    可以轻松修复添加

    AND amount_owed<>subquery.balance
    

    到触发器中查询的WHERE 子句。但是,将触发器更改为 BEFORE UPDATE 会更好,为了保持一致性,它甚至应该是检查 return_date 是否已填充的 BEFORE INSERT OR UPDATE 触发器。

    这看起来像是一个练习练习,所以你自己试试之前的触发器。

    【讨论】:

    • 谢谢,添加后我尝试将触发器更改为BEFORE INSERT OR UPDATE。现在我没有收到任何错误,但 amount_owed 列没有更新为表达式。这一切都是为了我的家庭 DVD 出租店,我正在创建一个数据库供他们用来出租 DVD。我的大部分查询和表格都是通过研究堆栈溢出和网络上的其他教程来完成的。
    • @Pugy365 在触发器不同之前,您的表中还没有日期,因此您必须使用NEW 来访问记录。如果我有时间,我会尝试更新答案。但老实说,我不知道 DVD 出租仍然存在。
    • 是的,那里还有一些,我们在一个小镇上经营它,所以我们仍然有很多在该国没有互联网接入的人租用 DVD。感谢您的帮助,我会在触发器之前弄清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 2016-09-30
    • 2022-01-01
    • 2017-07-18
    相关资源
    最近更新 更多