menu

Questions & Answers

postgres function for loop

I have an orders table and an order_products_items table. The order_products_items has these fields:

  • order_id
  • product_id
  • quantity
  • price

I am trying to create a calculated_field: calculated_total_products_price in the orders table through a before insert trigger function that would calculate the total order price by looping through all the order_products_items related to the order and multiplying the quantity with the price for every order item.

This is my failed attempt in doing so:

CREATE OR REPLACE FUNCTION public.fn_trigger_total_order_price()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
declare total float := 0.0;
        product record;
  BEGIN
    FOR product IN
      SELECT itm.price, itm.quantity
      FROM order_products_items itm
        INNER JOIN orders ord
        ON itm.order_id  = ord.id
      WHERE ord.id = NEW.id
        LOOP
            total = total + (product.price * product.quantity);
        END LOOP;

      NEW.calculated_total_products_price := total;
      RETURN NEW;
  END;
  $function$
;

The trigger looks like this:

CREATE TRIGGER fn_trigger_total_order_price BEFORE INSERT ON public.orders
  FOR EACH ROW EXECUTE PROCEDURE fn_trigger_total_order_price();

Somehow, I do not get any errors, but always get 0 as a result.

Am I missing something? or is there a better/more efficient way of approaching this?

Many thanks.

Comments:
2023-01-17 00:49:05
Why don’t you use SUM() in an aggregate? You almost never need a loop
Answers(1) :

You don't need a loop in postgres to achieve this.

A simple AGGREGATION query would do.

Something like

SELECT SUM(quantity * price) 
FROM order_products_items
WHERE order_id = NEW.id

You also don't really need to mess with a trigger if you don't want to.

Just make a view out of the query below and relate it to the orders table as something like order_totals

SELECT order_id, SUM(quantity * price) order_total
FROM order_products_items
GROUP BY order_id