Я работаю с розничной торговлей.
В розничной торговле у нас есть поставщики, которые поставляют продукты, и у нас есть клиенты, которые покупают эти продукты. Иногда случается, что два разных поставщика поставляют один и тот же продукт почти в один и тот же день. Поэтому я должен выяснить, какие продукты были проданы по первому предложению и какие продукты были проданы по второму предложению, используя алгоритм 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 |
+-----------+----------------------------+---------+------------+----------+-------------+