物料清单(Bill of Material, BOM),是制造执行系统 (manufacturing execution system,MES)和企业资源计划系统(Enterprise Resource Planning,ERP)里面必不可少的一个表,这个表最大的特点就是由无数棵树组成的森林,而且树之间还有交叉(共通枝叶),数据量比较大,在数据库二维表中以递归方式存储,对这个表的检索和操作是系统中比较重要的一个组成部分。下面简单写写数据的检索,主要涉及Sql server2008和oracle11中的检索方式。

1Sql server2008 中的两种检索模式:

1) 存储过程方式,递归有32层的限制,而且游标很麻烦,没有oracle的那种行变量,很罗嗦。

View Code

 1 ALTER PROCEDURE [DBO].[GETBOMTREE](
 2     @UPCD  CHAR(25),
 3     @LEVEL  INT
 4 ) AS
 5 BEGIN
 6     SET NOCOUNT ON;
 7     DECLARE @FACCD CHAR(12), @UPPERCD CHAR(25),
 8     @SEQ INT,@LOWERCD CHAR(25),@NEWLEVEL INT;
 9
10     IF @LEVEL = 0
11     BEGIN
12         SET @LEVEL=1;
13     END
14
15     DECLARE BOM_CURSOR CURSOR LOCAL FOR   --注意是LOCAL游标
16 SELECT FAC_CD,UPPER_ CD,USE_SEQ,ISNULL(LOWER_ CD,'')
17         FROM T_BOM
18         WHERE UPPER_CD = @UPCD ;
19
20     OPEN BOM_CURSOR;
21
22     FETCH NEXT FROM BOM_CURSOR
23     INTO @FACCD,@UPPERCD,@SEQ,@LOWERCD ;
24
25     --
26     IF @@FETCH_STATUS <>0
27     BEGIN
28         CLOSE BOM_CURSOR;
29         DEALLOCATE BOM_CURSOR;
30
31         RETURN ;
32     END
33
34     --
35     WHILE @@FETCH_STATUS = 0
36     BEGIN
37         --插入数据进入临时表(实际为物理表,每次执行时删除该表数据,还要增加终端号或用户名区分多用户操作,这里省略)
38         INSERT INTO T_BOM_TMP(
39             FAC_CD,UPPER_CD,USE_SEQ,LOWER_CD,LEVEL
40         ) VALUES (
41             @FACCD,@UPPERCD,@SEQ,@LOWERCD,@LEVEL
42         );
43
44         --调用本身
45         SET @NEWLEVEL=@LEVEL + 1;
46         EXEC DBO.GETBOMTREE @LOWERCD,@NEWLEVEL;
47
48         FETCH NEXT FROM BOM_CURSOR
49             INTO @FACCD, @UPPERCD,@SEQ,@LOWERCD ;
50     END
51
52     CLOSE BOM_CURSOR;
53     DEALLOCATE BOM_CURSOR;
54 END

2) CTE方式,该方式无递归限制,并且代码简洁,是第一选择。

View Code

 1 WITH BOM_CTE AS
 2
 3 (
 4
 5     SELECT *,1 AS ILEVEL FROM T_BOM WHERE
 6
 7       FAC_CD   = 'FAC01' AND    --工厂代码
 8
 9       UPPER_CD = 'AAA'   --要查找的根节点
10
11     UNION ALL
12
13     SELECT P.*,D.ILEVEL + 1 AS ILEVEL
14
15     FROM T_BOM AS P
16
17        INNER JOIN BOM_CTE AS D ON
18
19            P.FAC_CD    = D.FAC_CD   AND
20
21            P.UPPER_CD = D.LOWER_CD
22
23 )
24
25 SELECT * FROM BOM_CTE

2ORACLE11中的两种方式

1)存储过程,我只写包体的主要部分(由于没有环境,代码没有经过测试)

View Code

 1 --插入临时表数据
 2
 3   PROCEDURE INS_BOM_TMP(V_ROW_BOM T_BOM_TMP%ROWTYPE) IS  BEGIN
 4     INSERT INTO T_BOM_TMP VALUES V_ROW_BOM;
 5   END INS_BOM_TMP;
 6
 7  --主要递归过程
 8
 9 PROCEDURE GET_BOM(V_FAC_CD T_BOM.FAC_CD%TYPE,
10
11 V_UPPDER_CD T_BOM.UPPER_CD%TYPE,
12
13 LEVEL NUMBER(10,0)) IS
14
15 CURSOR V_BOM_CURSOR IS
16       SELECT * FROM T_BOM WHERE FAC_CD = V_FAC_CD AND UPPER_CD= V_UPPDER_CD;
17     V_CUR V_BOM_CURSOR%ROWTYPE;
18     V_ROW T_BOM_TMP%ROWTYPE;
19 BEGIN
20     FOR V_CUR IN V_BOM_CURSOR LOOP
21         V_ROW.FAC_CD           := V_CUR.FAC_CD;
22         V_ROW.UPPER_ITEM_CD    := V_CUR.UPPER_CD;
23         V_ROW.USE_SEQ          := V_CUR.USE_SEQ;
24
25     V_ROW.LOWER_ITEM_CD    := V_CUR.LOWER_CD;
26         V_ROW.LEVEL         := LEVEL;
27         INS_BOM_TMP (V_ROW);   --插入临时表
28
29 GET_BOM(V_FAC_CD, V_CUR.LOWER_CD, LEVEL+1);  --递归调用
30     END LOOP;
31 EXCEPTION
32     WHEN OTHERS THEN
33       --定义一个错误函数记录错误日志
34       WRITE_ERR_LOG(PACKAGE_ID,'GET_BOM', SQLERRM);
35 END GET_BOM;

  个人很喜欢oracle的存储过程编写,变量声明方式很好,函数也很丰富,尤其行变量很方便。

2) ORACLE的递归语句(相当简洁)

View Code

SELECT FAC_CD,UPPER_CD,USE_SEQ,LOWER_CD,LEVEL  --LEVEL是关键字
FROM T_BOM
WHERE LEVEL <= 3 AND FAC_CD='FAC01'
START WITH UPPER_CD='AAA'   --根节点
CONNECT BY PRIOR LOWER_CD=UPPER_CD --从根到叶
--CONNECT BY  LOWER_CD=PRIOR UPPER_CD --从叶到根
ORDER SIBLINGS BY USE_SEQ   --子节点内部排序

3、LINQ方式获取BOM(Linq to Sql,递归)

View Code

 1 void Main()
 2
 3 {
 4
 5     var query=GetBom("AAA");
 6
 7      Console.WriteLine("Upper Code");
 8
 9      query.ToList().ForEach(q=>Console.WriteLine("{0}",q.UPPER_CD));
10
11 }
12
13
14
15 public IEnumerable<T_BOM> GetBom(string UpperCD)
16
17 {
18
19     var query = from b in T_BOM
20
21           where b.UPPER_CD  == UpperCD
22
23           select b;
24
25
26
27     return  query.ToList().Concat(query.ToList().SelectMany(t => GetBom(t.LOWER_CD)));
28
29 }

  在我本地机上用该方法在从10万多条数据中获取321条的一棵树,用时2秒多(LinqPad中执行的结果),无论用自己写的存储过程或CTE方式,都只有0.2秒左右(Management studio中执行的结果)。另外,观察LINQ生成的SQL语句,发现数据重复获取,由于效率低下,我采用了EF中用存储过程方式,不过总有种“如鲠在喉”的感觉,希望哪位大师能告诉我EF下如何递归大数据量的问题,不胜感激。

补充:上面的代码我也是网上找的一段代码,由于假期有点空,就仔细看了看代码,稍微变更一下,去掉了重复获取数据,性能有很大提高,0.6秒多,代码如下

View Code

 1 void Main()
 2 {
 3     var query=GetBom("AAA");
 4      Console.WriteLine("Upper Code");
 5      query.ToList().ForEach(q=>Console.WriteLine("{0}",q.UPPER_CD));
 6 }
 7
 8 public IEnumerable<T_BOM> GetBom(string UpperCD)
 9 {
10     var list = (from b in T_BOM
11           where b.UPPER_CD  == UpperCD
12           select b).ToList();
13
14     return  list.Concat(list.SelectMany(t => GetBom(t.LOWER_CD)));
15 }

  以上代码性能有很大提高,但总归有一定的欠缺。不过技术是死的,设计是活的,可以扩充“深度”字段和“页标识”字段来减少代码的复杂度和获取数据的灵活度,比如叶子是已知的情况,就不再去递归检索,在Web项目中还可以通过AJAX展开枝叶。不过要注意,如果树有交叉,“深度”字段是无意义的。也有的设计采用触发器自动更新深度字段,该方式虽然比较好,但用ORM框架总是希望数据库无关的。当然,各种技术和设计的优缺点都有,仁者见仁,智者见智罢了。

4、附上Tree代码生成函数(winform程序,VB.net代码,非递归)

View Code

 1 Private Sub CreateBomTree(dtBom As DataTable, tnParent As Windows.Forms.TreeNode)
 2     Dim tnChild As System.Windows.Forms.TreeNode
 3     Dim iLevel As Int16 = 1         '层号
 4     For Each dr As DataRow In dtBom.Rows
 5         tnChild = New Windows.Forms.TreeNode
 6         tnChild.Name = dr("LOWER_CD").ToString().Trim()
 7         tnChild.Text = dr("USE_SEQ") & " " & dr("LOWER_DESC").ToString().Trim()
 8         If dr("LEVEL") = iLevel Then
 9             tnParent.Nodes.Add(tnChild)
10         ElseIf dr("LEVEL") > iLevel Then
11             iLevel = dr("LEVEL")
12             tnParent = tnParent.LastNode
13             tnParent.Nodes.Add(tnChild)
14         Else
15             For i As Int16 = dr("LEVEL") To iLevel - 1
16                 tnParent = tnParent.Parent
17             Next
18
19             iLevel = dr("LEVEL")
20             tnParent.Nodes.Add(tnChild)
21         End If
22     Next
23 End Sub

转载于:https://www.cnblogs.com/Kylin98/archive/2012/10/06/2712928.html

ERP中递归获取物料清单(BOM)方法相关推荐

  1. linux java获取路径_linux中java获取路径的方法

    linux中java获取路径的方法 发布时间:2020-05-06 11:11:26 来源:亿速云 阅读:700 作者:小新 今天小编给大家分享的是linux中java获取路径的方法,相信很多人都不太 ...

  2. Windows中快速获取文件目录的方法

    计算机使用时间越长,硬盘中保存的文件就会越来越多,如果不对这些众多的文件创建合适的目录,日后要寻找某个文件将变得非常困难.为了提高文件定位的效率创建方便快捷的文件目录,下面有如下几则快速生成文件目录的 ...

  3. 安卓中为了获取context的方法和区别(getContext,getActivity,this,mainActivity.this等)

    最近在着手做项目的时候,发现在需要context的时候,不同的类或者位置中需要用不同的方法聊火气context对象.在百度谷歌查找资料以及问周围的大神之后,总结了大概如下的内容: 1.MainActi ...

  4. php中count获取多维数组长度的方法

    转自:http://www.jb51.net/article/57021.htm 本文实例讲述了php中count获取多维数组长度的实现方法.分享给大家供大家参考.具体分析如下: 先来看看下面程序运行 ...

  5. 【DB笔试面试597】在Oracle中,获取执行计划有哪几种方法?

    ♣题目部分 在Oracle中,获取执行计划有哪几种方法? ♣答案部分 一般来说,有如下几种获取执行计划的方式: 1.AUTOTRACE方式 AUTOTRACE是Oracle自带的客户端工具SQL*Pl ...

  6. ERP中BOM的数据库设计与实现

    引言在企业资源计划(Enterprise Resource Planning,ERP)中, 物料清单(Bill of Materials,BOM)是系统中的最基本资料,用来描述产品的零部件组成和零部件 ...

  7. ERP中BOM变更操作的简单操作

    BOM变更 BOM变更在ERP中时不时的会发生,BOM变更不仅仅是只是BOM版本变更一下就结束了,往往旧版本的BOM相关正在生产中的工单如何处理才是最重要,也是最麻烦的事情. 生产过程节点这张图进行理 ...

  8. php中多维数组的长度,php中count获取多维数组长度的方法

    这篇文章主要介绍了php中count获取多维数组长度的方法,实例分析了数组的原理并总结了数组长度计算的方法,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了php中count获取多维数组长度的实 ...

  9. java 中lock,java中lock获取锁的四种方法

    在java接口中会存放着许多方法,方便线程使用时的直接调用.对于lock接口大家都不陌生,我们已经初步对概念进行了理解.那么在获取锁的方法上想必还不是很清楚.下面我们就lock获取锁的四种方法分别进行 ...

最新文章

  1. Python中最好用的命令行参数解析工具
  2. boost::combine相关的测试程序
  3. 如何拼局域网所有ip_求助 家庭网络如何布线让所有网口在同一个局域网内
  4. mfa助听器设备能否在android,助听器的蓝牙功能到底有什么用,购买的价格,以及购买时要注意什么等问题...
  5. SQL Server安全性和基于策略的管理–高级条件
  6. 3dmax中为人物添加动作的流程
  7. Python入门--字符串的连接和替换,replace,join
  8. Unix/Linux笔记全集
  9. 使用EasyRecovery简单修复视频
  10. 电机控制park变换公式推导
  11. 北大青鸟c语言课后答案,北大青鸟C语言实现.ppt
  12. 我的上岸之旅——深圳工业大学
  13. 一级计算机脚注怎么加,word怎么插入脚注 word添加脚注图文教程
  14. 系统的用户分析方法及分析内容
  15. 34、CSS高频前端面试题之CSS基础
  16. Android Material Design简单使用 http://www.cnblogs.com/android-blogs/p/5632103.html
  17. 直流斩波电路在matlab中的建模与仿真,基于MATLAB/Simulink的直流斩波电路分析
  18. 【2022 CCF BDCI 文心大模型创意项目】DIY绘本
  19. 单点登录、统一认证解决方案(一)
  20. linux 路由转发 ipv6,IPv6路由

热门文章

  1. 微波炉定时c语言程序,微波炉定时器—微波炉定时器与微波炉原理
  2. DWARF格式对于debug信息的支持
  3. 深度解读如何在H5中完美融入VR技术
  4. 计算机科学 实用书籍
  5. 视频加密技术详解一机一码怎么用?
  6. RocketMQ助力编程猫构建稳定的业务系统
  7. 轮转数组 (java)
  8. 计算机操作员技术工作总结,计算机操作员工作总结.doc
  9. IE中js出现拒绝访问问题
  10. JavaScript时钟(指针式样的)