2

I'm trying to run a procedure/function when a table gets updated (insert/delete/update), however, the function doesn't appear to get run when the trigger occurs or the trigger doesn't get triggered on an insert.

Function and Trigger:

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 call:

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());

The stored procedure works as expected, and when I run it solo I get what I want. Running it from a trigger is failing with every way I attempt, so what's the correct way to run a trigger that executes a working procedure on a table update?

For context, this is based off of the dvd rental database from the postgres tutorial website.


Edit

stored procedure:

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;

To answer Adrian Klaver's other questions:

  • Yes, and that's intentional but open to change.
  • Because it is a requirement, a silly one, but still required.

I have also attempted to run the trigger as so:

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

In case running per row was needed, however, that also does not execute the procedure so the table I'm trying to update never receives any data.

12
  • 1) What is get_top_ten_rentals() doing? 2) What are the errors you get when you do the INSERT? 3) You know you are running this per statement vs per row? 4) Why not make get_top_ten_rentals() a function so you can use it directly in the trigger? Add answers as update to your question. Commented Nov 28, 2021 at 17:14
  • @AdrianKlaver see edits to question, please Commented Nov 28, 2021 at 17:27
  • 4
    @CodeLee, man! Leave the weekends for resting and get back the following Monday! I'm pretty sure you are tired: the trigger is for UPDATE, and you are executing an INSERT! Commented Nov 28, 2021 at 17:32
  • 1
    See here plpgsql trigger Example 43.4. A PL/pgSQL Trigger Function for Auditing. It lays out the pattern you would need to follow. Commented Nov 28, 2021 at 17:40
  • 1
    @MarcusViniciusPompeu: there's no updated pseudo table in SQL Server - only inserted and deleted. For an UPDATE, the inserted table contains the new values after the UPDATE operation, while deleted contains the values that existed before the UPDATE... Commented Nov 28, 2021 at 17:49

1 Answer 1

1

To fire your trigger for all data change events, code the event as 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()

Since the top 10 data depends only on data in tables, and not the event (insert, update or delete) that caused the data to change, the trigger may be safely defined as one trigger for all data change events.

Sign up to request clarification or add additional context in comments.

2 Comments

Except that is not going to work unless you make the function 'aware' of what operation is performed and what to do in each operation case. So this not an answer, but a comment. To make it an answer update it to include the necessary function mechanics to make the trigger actually work.
@AdrianKlaver This works as-is. There is no more coding required anywhere. The trigger is just a wrapper for the procedure, which in turn just refreshes the top 10 list. The top 10 calculation does not depend on the kind of event - any change (insert, update or delete) to the rental table may affect the top 10 data and the refresh calculation is the same regardless.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.