计算FIFO SQL中的价格

问题描述 投票:0回答:1

使用Postgres 11

使用FIFO,我想计算从库存中取出的物品的价格,以跟踪总库存的价值。

数据集如下:

ID  | prodno | amount_purchased | amount_taken | price | created_at
uuid  13976    10                 NULL           130     <timestamp>  
uuid  13976    10                 NULL           150     <timestamp>
uuid  13976    10                 NULL           110     <timestamp>
uuid  13976    10                 NULL           100     <timestamp>
uuid  13976    NULL                 14           ??      <timestamp>

在使用amount_taken插入行之前,我需要计算14个项目中每个项目的平均价格,在这种情况下是135,71,但如何计算这个相对有效?

我最初的想法是将行委托给两个临时表,一个是amount_taken为null,另一个是非空的,然后计算所有行,但看到这个表可能变得相当大,相当快(因为大多数当时,只有1个项目将从库存中获取),我担心这在短期内会是一个不错的解决方案,但会随着表格变大而放慢速度。那么,什么是互联网更好的解决方案?

postgresql fifo
1个回答
3
投票

鉴于此设置:

CREATE TABLE test (
    id int
    , prodno int 
    , quantity numeric
    , price numeric 
    , created_at timestamp
);
INSERT INTO test VALUES
    (1, 13976, 10,    130, NOW())
    , (2, 13976, 10,  150, NOW()+'1 hours')
    , (3, 13976, 10,  110, NOW()+'2 hours')
    , (4, 13976, 10,  100, NOW()+'3 hours')
    , (5, 13976, -14, NULL, NOW()+'4 hours')
    , (6, 13976, -1, NULL, NOW()+'5 hours')
    , (7, 13976, -10, NULL, NOW()+'6 hours')
    ;

那么SQL

SELECT id, prodno, created_at, qty_sold
    -- 5
    , round((cum_sold_cost - coalesce(lag(cum_sold_cost) over w, 0))/qty_sold, 2) as fifo_price 
    , qty_bought, prev_bought, total_cost
    , prev_total_cost
    , cum_sold_cost
    , coalesce(lag(cum_sold_cost) over w, 0) as prev_cum_sold_cost
FROM (
    SELECT id, tneg.prodno, created_at, qty_sold, tpos.qty_bought, prev_bought, total_cost, prev_total_cost
        -- 4
        , round(prev_total_cost + ((tneg.cum_sold - tpos.prev_bought)/(tpos.qty_bought - tpos.prev_bought))*(total_cost-prev_total_cost), 2) as cum_sold_cost 
    FROM (
      SELECT id, prodno, created_at, -quantity as qty_sold
          , sum(-quantity) over w as cum_sold
      FROM test
      WHERE quantity < 0
      WINDOW w AS (PARTITION BY prodno ORDER BY created_at)
    -- 1
    ) tneg 
    LEFT JOIN (
      SELECT prodno
          , sum(quantity) over w as qty_bought
          , coalesce(sum(quantity) over prevw, 0) as prev_bought
          , quantity * price as cost                              
          , sum(quantity * price) over w as total_cost
          , coalesce(sum(quantity * price) over prevw, 0) as prev_total_cost
      FROM test
      WHERE quantity > 0
      WINDOW w AS (PARTITION BY prodno ORDER BY created_at)
          , prevw AS (PARTITION BY prodno ORDER BY created_at ROWS BETWEEN unbounded preceding AND 1 preceding)
    -- 2
    ) tpos 
    -- 3
    ON tneg.cum_sold BETWEEN tpos.prev_bought AND tpos.qty_bought 
        AND tneg.prodno = tpos.prodno
    ) t
WINDOW w AS (PARTITION BY prodno ORDER BY created_at)

产量

| id | prodno | created_at                 | qty_sold | fifo_price | qty_bought | prev_bought | total_cost | prev_total_cost | cum_sold_cost | prev_cum_sold_cost |
|----+--------+----------------------------+----------+------------+------------+-------------+------------+-----------------+---------------+--------------------|
|  5 |  13976 | 2019-03-07 21:07:13.267218 |       14 |     135.71 |         20 |          10 |       2800 |            1300 |       1900.00 |                  0 |
|  6 |  13976 | 2019-03-07 22:07:13.267218 |        1 |     150.00 |         20 |          10 |       2800 |            1300 |       2050.00 |            1900.00 |
|  7 |  13976 | 2019-03-07 23:07:13.267218 |       10 |     130.00 |         30 |          20 |       3900 |            2800 |       3350.00 |            2050.00 |

  1. tneg包含有关销售数量的信息 | id | prodno | created_at | qty_sold | cum_sold | |----+--------+----------------------------+----------+----------| | 5 | 13976 | 2019-03-07 21:07:13.267218 | 14 | 14 | | 6 | 13976 | 2019-03-07 22:07:13.267218 | 1 | 15 | | 7 | 13976 | 2019-03-07 23:07:13.267218 | 10 | 25 |
  2. tpos包含有关购买数量的信息 | prodno | qty_bought | prev_bought | cost | total_cost | prev_total_cost | |--------+------------+-------------+------+------------+-----------------| | 13976 | 10 | 0 | 1300 | 1300 | 0 | | 13976 | 20 | 10 | 1500 | 2800 | 1300 | | 13976 | 30 | 20 | 1100 | 3900 | 2800 | | 13976 | 40 | 30 | 1000 | 4900 | 3900 |
  3. 我们将tneg中的行与tpos中的行匹配,条件是cum_sold介于qty_boughtprev_bought之间。 cum_sold是累计销售量,qty_bought是购买的累计金额,prev_boughtqty_bought的先前值。 | id | prodno | created_at | qty_sold | cum_sold | qty_bought | prev_bought | total_cost | prev_total_cost | cum_sold_cost | |----+--------+----------------------------+----------+----------+------------+-------------+------------+-----------------+---------------| | 5 | 13976 | 2019-03-07 21:07:13.267218 | 14 | 14 | 20 | 10 | 2800 | 1300 | 1900.00 | | 6 | 13976 | 2019-03-07 22:07:13.267218 | 1 | 15 | 20 | 10 | 2800 | 1300 | 2050.00 | | 7 | 13976 | 2019-03-07 23:07:13.267218 | 10 | 25 | 30 | 20 | 3900 | 2800 | 3350.00 |
  4. 分数 ((tneg.cum_sold - tpos.prev_bought)/(tpos.qty_bought - tpos.prev_bought)) as frac 衡量cum_soldqty_bought之间prev_bought的位置。我们使用这个分数来计算cum_sold_cost,这是与购买cum_sold项目相关的累积成本。 cum_sold_cost位于fracprev_total_cost之间的total_cost距离。
  5. 一旦获得cum_sold_cost,您就拥有了计算边际FIFO单位价格所需的一切。对于tneg的每一行,cum_sold_cost与其先前值之间的差异是qty_sold的成本。 FIFO价格只是这个成本与qty_sold的比率。
© www.soinside.com 2019 - 2024. All rights reserved.