SAP的库存报表一直都是很令人头疼的。
因为出入库业务非常复杂,导致库存逻辑也非常复杂,本文仅对库存逻辑中的历史库存部分,进行详细的解释,并提供一些实用高效的代码,希望能帮到大家。
示例
以普通库存的普通库存数量为例,直接上例子。
物料:A
工厂:0001
库存地点:0100
时间来到2017年5月,为物料A在库存地点初始化库存,假设数量为100。此时:
MARD表
对主键A-0001-0100,产生一条记录,其LFGJA、LFMON的值为2017、05,数量(这里均指普通库存数量)为100。
MARDH表
对主键A-0001-0100-2017-04,产生一条记录,其数量值均为0
(MARDH比MARD的主键字段多了年度和月份)
(注意:
这里说的2017年5月,指的是在2017年5月时,做当期的账务。
而如果在2018年2月打开2017年5月的账期,并且在2017年5月进行初始化库存记账的话,MARD表中的年月是201802,MARDH表中的数据则会有两条,多出一条A-0001-0100-2017-05的数据,数量值为100)
时间来到2017年6月,物料A在0001-0100出库数量10
MARD表
对主键A-0001-0100,年月变为201706,数量值变为90
MARDH表
新增一条A-0001-0100-2017-05的记录,数量值为100
(年月为上一个月)
时间来到2017年7月和8月,物料A无任何变化
MARD表
无变化
MARDH表
无变化
时间来到2017年9月,物料A在0001-0100出库数量20
MARD表
对主键A-0001-0100,年月变为201709,数量值变为70
MARDH表
新增一条A-0001-0100-2017-08的记录,数量值为90
(年月为上一个月)
之后,物料A的库存一直未变化,时间来到2018年2月6日。
这时候打开2018年3月的账期,在2018年3月出库数量5。
MARD表
对主键A-0001-0100,年月为201803,数量值为65
MARDH表
存在四条记录
A-0001-0100-2017-04 0
A-0001-0100-2017-05 100
A-0001-0100-2017-08 90
A-0001-0100-2018-02 70(刚刚新增的)
而实际情况中,月底的库存情况如下:
201704 0
201705 100
201706 90(6月出库10)
201707 90
201708 90
201709 70(9月出库20)
201710 70
201711 70
201712 70
201801 70
201802 70
201803 65(3月出库5,且假设3月不再有出库)
结合到表MARD和MARDH,我们发现取201704、201705、201708、201802的月底库存,还都是很方便的,因为MARDH中有对应的主键。
但是如果要取2017年6月底的库存,该怎么办呢?
分析解释
根据实际库存的结果和MARDH表的数据,我们可以分析得知,如果要取物料在某月底的库存数据,要在表MARDH中寻找月份大于等于查询月份,且与查询月份最接近的数据。
即:
要取201706月底的数据,就要找MARDH中大于等于201706且与之最接近的201708的数据,结果为90。
要取201711月底的数据,就要找MARDH中大于等于201711且与之最接近的201802的数据,结果为70。
要取201611月底的数据,就要找MARDH中大于等于201611且与之最接近的201704的数据,结果为0。
在这里有个ABAP的知识如下:
取某一个月月底的普通库存数据
select single * into ls_mardh from mardh where
matnr = 'A'
and werks = '0001'
and lgort = '0100'
and ( lfgja > p_lfgja or ( lfgja = p_lfgja and lfmon >= p_lfmon) ).
取多个物料多个月月底的普通库存数据
select * into table lt_mardh from mardh where
matnr in s_matnr
and werks in s_werks
and lgort in s_lgort.
sort lt_mardh by matnr werks lgort lfgja lfmon.
"先根据二分查找,查找到大于等于当前条目且最接近当前条目的索引
read table lt_mardh with key …… binary search transporting no fields.
(请详细测试或查看帮助系统,以了解二分查找的这个神奇作用)
"根据索引读取内表
read table lt_mardh index sy-tabix into ls_mardh.
if sy-subrc = 0
and ls_mardh-matnr = p_matnr
and ls_mardh-werks = p_werks
and ls_mardh-lgort = p_lgort.
"ls_mardh就是你要找的数据
endif.
但是问题还没有结束。
假如从现在开始到了2018年10月,我们对物料A在0001-0100无任何变动,那么表MARD和MARDH的数据也就不会变。
按照刚才的逻辑,我们只能取到该物料在201802及以前的数据,而201803及以后的库存一直都是65,存在于表MARD中。
所以,按照上述办法,在MARDH表中取不到库存数据的时候,MARD的数据就是其库存数据。
这样,在上面判断if sy-subrc = 0 and....的代码后面,我们可以加上ELSE,在ELSE里面,取MARD表的数据即可。
总结
1、取物料在某月底的库存数据时,首先要在表MARDH中寻找月份大于等于查询月份,且与查询月份最接近的数据
2、按照第一条,在MARDH表中取不到库存数据的时候,MARD的数据就是其库存数据
3、MARD表中的年、月,表示物料数量上一次发生变化时的年、月
4、MSPR、MSKA、MCHB等表中的库存逻辑,与MARD基本一致,也都存在对应的H表
5、MBEW、QBEW、EBEW等库存价值的逻辑,也是差不多的,也都存在对应的H表。但不应想当然的认为,对于同样一个物料,MARD和MBEW的年月是一致的。因为数量变更影响库存数量,数量变更和价值变更都会影响MBEW。而价值变更的来源不一定是数量变更
6、二分查找的妙用,还是请测试一下以加深理解吧
IOS/ANDROID用户打赏——赞赏码