亲爱的读者们,今天和大家分享”先进先出”案例。”先进先出”(FIFO)原则在仓库存储和库存管理中广泛应用。该原则假设最早进入仓库的商品或材料应当是第一个被出售或使用的。
在计算库存成本时,这种方法更准确地反映了货物的流动情况。具体实施方式如下:
1. 当一个新的产品批次到达时,它被放在库存的后面。
2. 当需要从库存中取出产品时,则优先取出最早入库的批次。
本次使用的是PostgreSQL数据库实现,话不多说,代码如下:
DO LANGUAGE 'plpgsql' -- 指定匿名块的语言,可省略默认为plpgsql
$BODY$
DECLARE
v_TABEXT int := 1; --用于判断流出表中是否还有数据
v_liuchu int := 1; --流出顺序
v_liuru int := 1; --流入顺序
v_budat varchar(10) := '2023-10-01'; --结账日期
BEGIN
--开始循环
WHILE v_TABEXT <> 0 loop
--循环体语句
--创建流出临时表定义,存储根基工厂、供应商、物料号、物料凭证、凭证日期升序的临时数据
DROP TABLE if EXISTS table_out_tmp
;
CREATE TEMPORARY TABLE table_out_tmp
(
mblnr varchar(20) NULL
, --物料凭证号
mjahr numeric(4) NULL
, --物料凭证年
zeile numeric(4) NULL
, --行项目
budat timestamp NULL
, --流出过账日期
bwart varchar(6) NULL
, --移动类型
matnr varchar(36) NULL
, --物料号
werks varchar(8) NULL
, --工厂
kunnr varchar(20) NULL
, --客户
lifnr varchar(20) NULL
, --供应商
menge numeric(13,3) NULL
, --数量
meins varchar(6) NULL
, --单位
menge_total_out numeric(13,3) NULL
, --累计流出
out_sequence int --流出顺序
)
on
commit preserve rows
;
-- 创建流入临时表定义,存储根基工厂、供应商、物料号、物料凭证、凭证日期升序的临时数据
DROP TABLE if EXISTS table_in_tmp
;
CREATE TEMPORARY TABLE table_in_tmp
(
mblnr varchar(20) NULL
, --物料凭证号
mjahr numeric(4) NULL
, --物料凭证年
zeile numeric(4) NULL
, --行项目
budat timestamp NULL
, --流出过账日期
bwart varchar(6) NULL
, --移动类型
matnr varchar(36) NULL
, --物料号
werks varchar(8) NULL
, --工厂
kunnr varchar(20) NULL
, --客户
lifnr varchar(20) NULL
, --供应商
menge numeric(13,3) NULL
, --数量
meins varchar(6) NULL
, --单位
zlldh varchar(20) NULL
, --领料单号
menge_total_in numeric(13,3) NULL
, --累计流入
in_sequence int --流入顺序
)
on
commit preserve rows
;
--将流出数据插入临时表
INSERT INTO table_out_tmp
SELECT
MBLNR
, MJAHR
, ZEILE
, budat
, bwart
, matnr
, werks
, kunnr
, lifnr
, menge
, meins
, SUM(menge) OVER (PARTITION BY werks,lifnr,matnr ORDER BY
budat,MBLNR ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as menge_total_out
, ROW_NUMBER()OVER (PARTITION BY werks,lifnr,matnr ORDER BY
budat,MBLNR ) as out_sequence
FROM
table1
WHERE
budat >= to_date(v_budat,'YYYY-MM-dd')
AND menge < 0
--AND matnr ='000000001030013291'
AND NOT EXISTS
(
SELECT *
FROM
table_target
WHERE
table1.mblnr = table_target.mblnr
AND in_menge >=0
)
;
--将流入数据插入临时表
INSERT INTO table_in_tmp
SELECT
table1.MBLNR
, table1.MJAHR
, table1.ZEILE
, table1.budat
, table1.bwart
, table1.matnr
, table1.werks
, table1.kunnr
, table1.lifnr
, COALESCE(in_menge,table1.menge) AS menge
, table1.meins
, table1.zlldh
, SUM(table1.menge) OVER (PARTITION BY table1.werks,table1.lifnr,table1.matnr ORDER BY
table1.budat,table1.MBLNR ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as menge_total_in
, ROW_NUMBER()OVER (PARTITION BY table1.werks,table1.lifnr,table1.matnr ORDER BY
table1.budat,table1.MBLNR ) as in_sequence
FROM
table1
LEFT JOIN
(
SELECT
in_mblnr
, in_mjahr
, in_zeile
, in_budat
, in_zlldh
, min(in_menge) AS in_menge
FROM
table_target
GROUP BY
in_mblnr
, in_mjahr
, in_zeile
, in_budat
, in_zlldh
)
AS table_target
ON
(
table_target.in_mblnr = table1.mblnr
AND table_target.in_mjahr = table1.mjahr
AND table_target.in_zeile = table1.zeile
AND table_target.in_budat = table1.budat
AND table_target.in_zlldh = table1.zlldh
)
WHERE
table1.budat >= to_date(v_budat,'YYYY-MM-dd')
AND table1.menge > 0
AND COALESCE (table_target.in_menge,0) >= 0
AND NOT EXISTS
(
SELECT *
FROM
table_target
WHERE
table1.mblnr = table_target.mblnr
AND table_target.in_menge < 0
)
;
--根据流出工厂、物料、供应商匹配流入时的凭证号、凭证年、行项目、领料单号
INSERT INTO table_target
(
SELECT
table_out_tmp.MBLNR
, table_out_tmp.MJAHR
, table_out_tmp.ZEILE
, table_out_tmp.budat
, table_out_tmp.bwart
, table_out_tmp.matnr
, table_out_tmp.werks
, table_out_tmp.kunnr
, table_out_tmp.lifnr
, table_out_tmp.menge
, table_out_tmp.meins
, table_in_tmp.MBLNR
, table_in_tmp.MJAHR
, table_in_tmp.ZEILE
, table_in_tmp.budat
, table_in_tmp.zlldh
, table_in_tmp.menge + table_out_tmp.menge AS in_menge
, now() load_date
FROM
table_out_tmp
LEFT JOIN
table_in_tmp
ON
table_out_tmp.werks = table_in_tmp.werks
AND table_out_tmp.lifnr = table_in_tmp.lifnr
AND table_out_tmp.matnr = table_in_tmp.matnr
WHERE
table_out_tmp.out_sequence = v_liuchu
AND table_in_tmp.IN_sequence = v_liuru
)
;
--COMMIT;
--判断流出
SELECT
count(*)
INTO
v_TABEXT
FROM
table_out_tmp
;
end loop;
END
$BODY$;
难点:
每一笔的出库数和进库数不是一一对应的。比如:订单A 1号进库数量为500,但是出库数量可以小于、等于、大于500,所以每次计算都需要库里剩余量和下次出库量作比较。
知识点:本次使用SQL实现”先进先出”原则,主要用到之前分享过窗口函数以及存储过程技术。
以下是采用FIFO策略的一些好处:
-
降低过期风险: 对于有保质期或易腐烂的商品特别重要,因为FIFO保证了最早入库的商品会被优先销售。
-
减少损耗: 长时间存储可能会导致一些商品的质量下降,通过FIFO可以尽快售出,从而降低损耗。
-
估值更准确: 在通货膨胀环境下,因为最早购买的库存成本较低,所以利润会被高估。这也更接近现实商品的流动情况。
然而,FIFO策略并不适用所有情况,比如对于无法移动或者储存需求特殊的商品,可能需要使用其他库存管理策略。
希望您喜欢今天的分享,数据处理总是充满挑战,但只要我们掌握了正确的工具和技巧,就能以更有效率的方式解决问题。记得关注我们哟,获取更多小知识。
原文始发于微信公众号(运维小九九):SQL技巧:实现“先进先出”
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/218585.html