在Postgresql中创建函数,将数据插入已更新的表行

时间:2016-01-17 17:34:52

标签: database postgresql

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

例如:

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

以下是我一直在尝试的一些事情,触发器执行该功能,但之后我收到错误。

功能代码:

BOOST_LOG_TRIVIAL

触发码:

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;

PGadmin III只是说"发生错误"当我尝试添加return_date并保存更改时。

2 个答案:

答案 0 :(得分:0)

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

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

可以轻松修复添加

AND amount_owed<>subquery.balance

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

看起来像练习练习,所以请自行尝试触发前。

答案 1 :(得分:0)

就像Jakub所说,你需要一个BEFORE UPDATE触发器来完成这项工作。这种触发器有两个重要特征:

  1. 您有一个OLD和一个NEW变量,它包含更新前行的值以及更新后的内容。您可以操作NEW变量,然后这些更改将保存到表中。
  2. 如果某些更改不合适,您可以中止整个更新。
  3. 根据您的情况,触发器功能看起来像这样:

    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_datereturn_date的类型为date(顾名思义)。如果它们是timestamp,您可以创建两个变量并EXTRACT()出租日期并返回到这些变量。

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

相关问题