Реализация FIFO в SQL - PullRequest
1 голос
/ 28 мая 2019

Я работаю с розничной торговлей. В розничной торговле у нас есть поставщики, которые поставляют продукты, и у нас есть клиенты, которые покупают эти продукты. Иногда случается, что два разных поставщика поставляют один и тот же продукт почти в один и тот же день. Поэтому я должен выяснить, какие продукты были проданы по первому предложению и какие продукты были проданы по второму предложению, используя алгоритм FIFO. И обновите таблицу с элементами корзины, чтобы указать поставщика для каждого элемента.

У меня есть две таблицы:

supplies

+----------------------------+-------------+---------+------------+----------+
| supply_date                | supplier_id | shop_id | product_id | quantity |
+----------------------------+-------------+---------+------------+----------+
| 2019-03-29 12:00:00.000000 | 5           | 2       | 1          | 110      |
+----------------------------+-------------+---------+------------+----------+
| 2019-03-29 16:00:00.000000 | 7           | 2       | 1          | 50       |
+----------------------------+-------------+---------+------------+----------+
| 2019-04-01 13:00:00.000000 | 6           | 3       | 8          | 30       |
+----------------------------+-------------+---------+------------+----------+
| 2019-04-02 16:00:00.000000 | 8           | 3       | 8          | 90       |
+----------------------------+-------------+---------+------------+----------+
| 2019-04-29 10:00:00.000000 | 1           | 5       | 6          | 25       |
+----------------------------+-------------+---------+------------+----------+

cartitems

+-----------+----------------------------+---------+------------+----------+
| id        | date                       | shop_id | product_id | quantity |
+-----------+----------------------------+---------+------------+----------+
| 515037984 | 2019-04-01 14:25:50.000000 | 2       | 1          | 30       |
+-----------+----------------------------+---------+------------+----------+
| 515043777 | 2019-04-02 13:47:52.000000 | 3       | 8          | 25       |
+-----------+----------------------------+---------+------------+----------+
| 515045460 | 2019-04-02 20:14:30.000000 | 2       | 1          | 80       |
+-----------+----------------------------+---------+------------+----------+
| 515046099 | 2019-04-09 09:55:53.000000 | 2       | 1          | 10       |
+-----------+----------------------------+---------+------------+----------+
| 515046332 | 2019-04-09 11:06:30.000000 | 2       | 1          | 5        |
+-----------+----------------------------+---------+------------+----------+

Я пробовал что-то, и это работает, но слишком медленно. Оператор UPDATE .. FROM работает очень медленно. Приведенная ниже функция использует алгоритм FIFO и обновляет таблицу cartitems со столбцом supplier_id.

CREATE OR REPLACE FUNCTION attach_suppliers(shop INTEGER, product INTEGER) RETURNS INTEGER AS $$
  DECLARE
    -- VARIABLES TO USE
    supply_quantity DECIMAL;
    var_supplier_id INTEGER;
    supply_date TIMESTAMP;
    sale_quantity DECIMAL;
    cartitem_id INTEGER;

    -- SIMPLE COUNTER
    updated_count INTEGER = 0;

    -- CURSOR FOR MOVING ROW BY ROW IN A QUERY WITH SUPPLIES
    supplies_cursor CURSOR FOR
      SELECT quantity, supplier_id, supply_date
      FROM supplies s
      WHERE s.shop_id = $1 AND s.product_id = $2
      ORDER BY s.supply_date ASC;

    -- CURSOR FOR MOVING ROW BY ROW IN A QUERY WITH CARTITEMS
    sales_cursor CURSOR (start_date TIMESTAMP) FOR
      SELECT id, quantity
      FROM cartitems s
      WHERE s.shop_id = $1 AND s.product_id = $2 AND s.date > start_date
      ORDER BY s.date ASC;

  BEGIN
    -- TEMP TABLES TO SAVE REFERENCE BETWEEN CART ITEM AND SUPPLIER
    CREATE TEMP table citem_supplier_mapping (
      _cartitem_id INTEGER,
      _supplier_id INTEGER
    );

    -- STARTING FROM THE FIRST ROW FROM BOTH TABLES
    OPEN supplies_cursor;

    FETCH NEXT FROM supplies_cursor INTO supply_quantity, var_supplier_id, supply_date;

    OPEN sales_cursor(start_date := supply_date);

    FETCH NEXT FROM sales_cursor INTO sale_quantity, cartitem_id;

    -- LOOP THROUGH CART ITEMS
    LOOP
      -- CURRENT ITERATION SHOWS US REFERENCE BETWEEN CART ITEM AND SUPPLIER
      supply_quantity := supply_quantity - sale_quantity;
      INSERT INTO citem_supplier_mapping (_cartitem_id, _supplier_id) VALUES (cartitem_id, var_supplier_id);
      updated_count := updated_count + 1;

      -- IF ALL SUPPLIED PRODUCTS WERE SOLD THEN GO TO THE NEXT SUPPLY
      IF supply_quantity <= 0 THEN
        FETCH NEXT FROM supplies_cursor INTO supply_quantity, var_supplier_id, supply_date;
        EXIT WHEN NOT FOUND;
      END IF;

      -- GO TO THE NEXT CART ITEM
      FETCH NEXT FROM sales_cursor INTO sale_quantity, cartitem_id;
      EXIT WHEN NOT FOUND;
    END LOOP;

    -- UPDATE CART ITEMS TABLE WITH `supplier_id` COLUMN TO MAKE REFERENCE
    UPDATE cartitems SET supplier_id = _supplier_id FROM citem_supplier_mapping WHERE id = _cartitem_id;

    -- CLEAN UP
    DROP TABLE citem_supplier_mapping;
    CLOSE supplies_cursor;
    CLOSE sales_cursor;

    RETURN updated_count;
  END; $$
  LANGUAGE plpgsql;

В результате я ожидаю такую ​​таблицу (или просто отображение между cartitem_id и supplier_id):

+-----------+----------------------------+---------+------------+----------+-------------+
| id        | date                       | shop_id | product_id | quantity | supplier_id |
+-----------+----------------------------+---------+------------+----------+-------------+
| 515037984 | 2019-04-01 14:25:50.000000 | 2       | 1          | 30       | 5           |
+-----------+----------------------------+---------+------------+----------+-------------+
| 515043777 | 2019-04-02 13:47:52.000000 | 3       | 8          | 25       | 6           |
+-----------+----------------------------+---------+------------+----------+-------------+
| 515045460 | 2019-04-02 20:14:30.000000 | 2       | 1          | 80       | 5           |
+-----------+----------------------------+---------+------------+----------+-------------+
| 515046099 | 2019-04-09 09:55:53.000000 | 2       | 1          | 10       | 7           |
+-----------+----------------------------+---------+------------+----------+-------------+
| 515046332 | 2019-04-09 11:06:30.000000 | 2       | 1          | 5        | 7           |
+-----------+----------------------------+---------+------------+----------+-------------+
...