Комплексная логическая функция Postgresql (plpgsql) - PullRequest
0 голосов
/ 06 октября 2019

Хорошо, у меня есть эти схемы

https://dbfiddle.uk/?rdbms=postgres_10&fiddle=56b0781c13dfb545e9f07f82da6ae34d

  • Каждый счет будет иметь набор продуктов, сохраненных в таблице bill_products
  • Этот bill_products будет доставлен и обновленслучайным образом в ближайшем будущем

Мне нужно сформулировать функцию, которая будет принимать входные данные jsonb как таковые

 [ 
      {
        bill_id : 1,
        product_id : 1,
        delivered: 50
      },
      {
        bill_id : 1,
        product_id : 2,
        delivered: 400
      } 
 ]  

Принимая вышеуказанный входной сигнал jsonb, функция должна обновить bill_products , а также вставить его в инвентарь таблицу. Также, если все bill_products были доставлены, он должен обновить утвержденное логическое значение до true в bill table

Я новичок в plpgsql, может кто-нибудь помочь мне сэто.

1 Ответ

0 голосов
/ 07 октября 2019

Полагаю, это должно быть сделано:

DO LANGUAGE plpgsql $$
DECLARE
    input CONSTANT jsonb := '...';
    delivery jsonb;
    updated bill_products;
BEGIN
    FOR delivery IN SELECT jsonb_array_elements(input) LOOP
        UPDATE bill_products
          SET delivered = delivered + (delivery->>'delivered')::numeric
          WHERE bill_id = (delivery->>'bill_id')::int
            AND pro_id = (delivery->>'product_id')::int
          RETURNING *
          INTO STRICT updated;
        INSERT INTO inventory(pro_id, quantity)
          VALUES (updated.pro_id, updated.delivered);
    END LOOP;
    UPDATE bill
      SET approved = NOT EXISTS (SELECT 1
                                 FROM bill_products
                                 WHERE bill_products.bill_id = bill.bill_id
                                   AND delivered < quantity)
      WHERE bill_id IN (SELECT DISTINCT (d->>'bill_id')::int
                        FROM jsonb_array_elements(input) d);
END;
$$;

( онлайн-демонстрация )

В качестве альтернативы использование простого SQL вместо цикла может быть еще проще:

WITH updates AS (
  UPDATE bill_products
  SET delivered = delivered + (delivery->>'delivered')::numeric
  FROM jsonb_array_elements(input) delivery
  WHERE bill_id = (delivery->>'bill_id')::int
    AND pro_id = (delivery->>'product_id')::int
  RETURNING pro_id, delivered
) INSERT INTO inventory(pro_id, quantity)
  SELECT * FROM updates;

( online demo )

Обратите внимание, что дублирование информации о доставке в таблицах inventory и bill_products не является хорошим дизайном базы данных. Возможно, вам следует опустить столбец bill_prodcts.delivered и вычислять сумму соответствующих записей инвентаря каждый раз, когда вам это нужно.

...