< 返回
bom中用到的数据库算法

ERP

我们经常在erp或其它一些系统中,需要这样的数据结构:bom的最顶层成品半成品和最底层所有原材料,不需要中间节点。这样,就需要求一颗树的所有或者是部分根节点。当然,在面向对象的设计中,一层一层的遍历,找出所有根节点并不难。但是,当一次需要对几万甚至几十万的成品、半成品来操作,并且bom结构又比较复杂(层次普遍比较多)的情况下,面向对象的设计效率将是一个很大的问题。最快的办法是直接在数据库中使用存储过程完成。

算法描述

下面在sql server中实现这个算法。

假设多层的bom存储在表tblbom中,直接对tblbom进行处理,处理完毕之后结果就是tblbom中的记录,表结构如下:

-----------------------------------------------------

tblbom (--制造工厂pplant nvarchar(8),--父料pitem nvarchar(20),--发料工厂cplant nvarchar(8),--子料citem nvarchar(20),--有效期开始effectivedate datetime,--有效期结束discontinuedate datetime,--用量usage decimal(18,6) )

-----------------------------------

处理过程中,创建临时表#i_temp_bom存放中间处理数据,在一系列循环中完成处理。

每次,我们将那些下层节点不是根节点的记录取出来,放入#i_temp_bom中。在这一次的循环中,我们把这些节点往下展开一层。

假如bom的结构如下图所示:

在tblbom中的数据如下:

实际上,算法将得到四个bom结构,在这个算法描述部分,我们只关注00001的展开情况。

第一次循环,将记录00001-00010、00001-00012、00012-00122这三条记录取到临时表#i_temp_bom中,因为这三条记录的下层节点不是根节点。 字串8

在第一次循环内,将这三条记录的下层节点进行展开。展开后的00001结构如下:

在tblbom中的数据如下:

现在,整个tblbom表中就只有00001-00122这一条数据还未展开到最底层。接下来,第二次循环中,即将这条记录展开到最底层。

最终得到00001的结构如下:

tblbom中的数据如下:

sql实现

create table #i_temp_bom

(

pplant nvarchar(8),

pitem nvarchar(20),

cplant nvarchar(8),

citem nvarchar(20),

effectivedate datetime,

discontinuedate datetime,

usage decimal(18,6)

)

INSERT into #i_temp_bom(pplant,pitem,cplant,citem,usage,effectivedate,discontinuedate)

select distinct a.pplant,a.pitem,a.cplant,a.citem,a.usage,a.effectivedate,a.discontinuedate

from tblbom a

inner join (select distinct pplant,pitem from tblbom)t on t.pplant=a.cplant and t.pitem=a.citem

while exists(select top 1 * from #i_temp_bom)

begin

INSERT into tblbom (pplant,pitem,cplant,citem,usage,effectivedate,discontinuedate)

select b.pplant,b.pitem,a.cplant,a.citem,a.usage*b.usage,

case when a.effectivedate>=b.effectivedate then a.effectivedate else b.effectivedate end,

case when a.discontinuedate<=b.discontinuedate then a.discontinuedate else b.discontinuedate end

from tblbom a

inner join #i_temp_bom b on b.cplant=a.pplant and b.citem=a.pitem

delete tblbom

from #i_temp_bom a

where tblbom.pplant=a.pplant and tblbom.pitem=a.pitem and tblbom.cplant=a.cplant and tblbom.citem=a.citem

truncate table #i_temp_bom

INSERT into #i_temp_bom(pplant,pitem,cplant,citem,usage,effectivedate,discontinuedate)

select distinct a.pplant,a.pitem,a.cplant,a.citem,a.usage,a.effectivedate,a.discontinuedate

from tblbom a

inner join (select distinct pplant,pitem from tblbom)t on t.pplant=a.cplant and t.pitem=a.citem

end

drop table #i_temp_bom

附加说明

不管bom的层级是多少,最多5次循环会将整个bom结构完全展开。

数据量大时,利用索引,包括临时表也可以创建索引,能够进一步加快执行。

不同的erp系统,bom表的数据结构会不一样,关键字等都可能不相同。上面的算法只是以一种最简单的bom结构为例进行说明。在针对具体的erp bom数据结构时,需要考虑更多的情况,否则算法中将存在bug。

实际上erp系统中,都会有类似半成品(或者半成品bom)、虚拟件(或者虚拟bom)等,有些类型需要继续展开下层,而有些是不需要,可以根据具体的情况和需求加上限制条件。如果可以提供一个成品、半成品列表,只需要这个列表中材料的bom结构,也可以运用到算法中,以缩小每次的数据范围。在这样的算法中,bom结构里的有些信息是没办法保留的,可能这些信息你也不需要,例如替代关系、工序等。