在SQL中实现FIFO

时间:2019-05-28 15:31:19

标签: sql algorithm fifo

我正在零售。 在零售中,我们有供应商提供产品,而我们有客户购买这些产品。有时会发生两个不同的供应商几乎在同一天提供相同产品的情况。因此,我必须使用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           |
+-----------+----------------------------+---------+------------+----------+-------------+

0 个答案:

没有答案