【问题标题】:How to trigger AFTER UPDATE in Postgres如何在 Postgres 中触发 AFTER UPDATE
【发布时间】:2022-01-05 18:24:50
【问题描述】:

我正在尝试在表被更新(插入/删除/更新)时运行一个过程/函数,但是,当触发器发生或触发器没有被触发时,该函数似乎没有运行插入。

函数和触发器:

CREATE OR REPLACE FUNCTION fn_rental_trigger() RETURNS TRIGGER AS $$
   BEGIN
    CALL get_top_ten_rentals();
    RETURN NULL;
   END; $$
LANGUAGE plpgsql;

CREATE TRIGGER tr_new_rentals
    AFTER UPDATE ON public.rental
    EXECUTE FUNCTION public.fn_rental_trigger();

插入调用:

INSERT INTO public.rental (rental_date, inventory_id, customer_id, return_date, staff_id, last_update)
VALUES (NOW(), 4030, 459, NOW() + interval '7 day', 1, NOW());

存储过程按预期工作,当我单独运行它时,我得到了我想要的。从触发器运行它在我尝试的每一种方式中都失败了,那么运行触发器以在表更新上执行工作过程的正确方法是什么?

就上下文而言,这是基于 postgres tutorial website 中的 dvd 出租数据库。


编辑

存储过程:

CREATE OR REPLACE PROCEDURE get_top_ten_rentals()

AS
$$

-- Start a tansaction to get the data
BEGIN
    
    -- clear out existing data to refresh list
    DELETE FROM report.top_ten_rentals;

    INSERT INTO report.top_ten_rentals (title, inventory_id, rating, length, times_rented, total)
    SELECT f.title AS title,
           r.inventory_id AS inventory_id,
           f.rating,
           fn_transform_length(f.length),
           COUNT(*) AS times_rented,
           SUM(p.amount) AS total
    FROM public.payment AS p
        JOIN public.rental AS r ON p.rental_id = r.rental_id
        JOIN public.inventory AS i ON r.inventory_id = i.inventory_id
        JOIN public.film AS f ON i.film_id = f.film_id
    GROUP BY r.inventory_id, f.title, f.rating, f.length
    ORDER BY total DESC
    LIMIT 10;

    -- Rollback when there is an exception to preserve data integrity
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
END;
$$

LANGUAGE plpgsql;

回答 Adrian Klaver 的其他问题:

  • 是的,这是有意的,但可以改变。
  • 因为这是一项要求,一个愚蠢的要求,但仍然是必需的。

我也尝试过这样运行触发器:

CREATE TRIGGER tr_new_rentals
    AFTER UPDATE ON public.rental
    FOR EACH ROW
      EXECUTE FUNCTION public.fn_rental_trigger();

但是,如果需要按行运行,那也不会执行该过程,因此我尝试更新的表永远不会收到任何数据。

【问题讨论】:

  • 1) get_top_ten_rentals() 在做什么? 2) 执行INSERT 时遇到什么错误? 3)你知道你是在每条语句还是每行运行这个? 4) 为什么不把get_top_ten_rentals() 做成一个函数,这样你就可以直接在触发器中使用它了?添加答案以更新您的问题。
  • @AdrianKlaver 请查看对问题的修改
  • @CodeLee,伙计!周末休息,下周一回来!我很确定你累了:触发器是 UPDATE,而你正在执行 INSERT
  • 参见此处plpgsql trigger 示例 43.4。用于审计的 PL/pgSQL 触发器函数。它列出了您需要遵循的模式。
  • @MarcusViniciusPompeu:SQL Server 中没有 updated 伪表 - 只有 inserteddeleted。对于UPDATEinserted 表包含UPDATE 操作之后的 值,而deleted 包含UPDATE 之前存在的值 ...

标签: sql postgresql stored-procedures triggers


【解决方案1】:

要触发所有数据更改事件的触发器,请将事件编码为INSERT OR UPDATE OR DELETE

CREATE TRIGGER tr_new_rentals
AFTER INSERT OR UPDATE OR DELETE ON public.rental
FOR EACH ROW
    EXECUTE FUNCTION public.fn_rental_trigger()

由于前 10 位数据仅取决于表中的数据,而不是导致数据更改的事件(插入、更新或删除),因此可以安全地将触发器定义为所有数据更改事件的一个触发器。

【讨论】:

  • 除非你让函数“知道”执行了什么操作以及在每个操作案例中要做什么,否则它不会起作用。所以这不是答案,而是评论。为了使它成为答案,请更新它以包含使触发器实际工作所需的功能机制。
  • @AdrianKlaver 这按原样工作。任何地方都不再需要编码。触发器只是该过程的一个包装器,它反过来只是刷新前 10 个列表。前 10 名的计算不取决于事件的类型 - 对租赁表的任何更改(插入、更新或删除)都可能影响前 10 名数据,并且无论如何刷新计算都是相同的。
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 2014-04-25
相关资源
最近更新 更多