高度难动态BOM成本计算 
成本计算成最下级算到最上级的。 BOM表 
        产品    产品数量  原料          原料数  单价 
BILLID  MGOODSID  MQTY  DGOODSID ITEMNO  DQTY  DPRICE 
584    A001        1    B001      1      1      ??  (半成品)    
584    A001        1    C001      2      2      5    (原料)    2个C001组成 
584    A001        1    D001      3      1      5  (原料) 
588    B001        1    E001      1      1      3    (原料) 
588    B001        1    F001      2      2      ??    (半成品)  2个F001组成 
560    F001        1    G001      1      1      2  (原料) 
560    F001        1    J001      2      2      2  (原料)    2个J001组成 树型结构如下: 
                      A001  *1 
            |              |            | 
        B001 *1          C001 *2    D001  *1 
    |        | 
  E001 *1    F001 *2 
            |      |        
          G001 *1  J001 *2 
求: 
1、要求结果按物料清单最底层原料起计算推算出半成品、成品的单价,希望能做成函数或存储过程。 MGOODSID  MQTY,  DGOODSID,  DQTY,  DPRICE,  DAM 
A001        1      B001      1      15        15  ---B001单价是算出来的 
A001        1      C001      2      5        10 
A001        1      D001      1      5        5 
B001        1      E001      1      3        3 
B001        1      F001      2      6        12  ---F001单价是算出来的 
F001        1      G001      1      2        2  
F001        1      J001      2      2        4 2、如果BOM数据量比较大时上面的方法运算就比较慢了,有没有办法只查询某货品如 A001时, 
只计算跟A001相关货品。 
WHERE M.GOODSID='A001'时的结果如下: 
MGOODSID  MQTY,  DGOODSID, DQTY,  DPRICE,  DAM 
A001        1      B001      1      15    15  ---B001单价是算出来的 
A001        1      C001      2      5      10 
A001        1      D001      1      5      5 

解决方案 »

  1.   

    以下是之前各位兄弟的回复供参考,
    http://topic.csdn.net/u/20090825/19/f1bddd50-ca59-431d-b4e3-745bba222798.html希望能有更优化的解决方案,谢谢!!
      

  2.   


    是呀,比较困难的,相信你们会帮我忙。
    BOM最多是6阶的,一般都是控制在5阶之内,希望在查询时能在20秒内能查出某货品的理论成本价,
    能帮我解决的再加100分,谢谢大家支持!
      

  3.   

    哥们,你也够执着的啊,呵呵
    看在200分的份上, 决定献丑了
    if object_id('[M_BOM]') is not null 
    begin
    drop table [M_BOM] ;
    end
    GO
    ------------------------------------------
    ------------------------------------------
    create table [M_BOM] (BILLID int,MGOODSID varchar(4),MQTY int, GOODSID varchar(4),ITEMNO int,QTY int,PRICE int);
    go
    ------------------------------------------
    ------------------------------------------
    insert into [M_BOM](BILLID ,MGOODSID ,MQTY , GOODSID ,ITEMNO ,QTY ,PRICE )
    select 584  ,  'A001' ,       1   , 'B001'   ,   1    ,  1   ,   NULL union all  
    select 584  ,  'A001'   ,     1  ,  'C001'  ,    2  ,    2  ,    5   union all
    select 584  ,  'A001'   ,     1  ,  'D001'   ,   3  ,    1  ,    5  union all
    select 588  ,  'B001'   ,     1  ,  'E001'  ,    1   ,   1   ,   3  union all
    select 588  ,  'B001'    ,    1  ,  'F001'  ,    2   ,   2   ,   NULL  union all
    select 560  ,  'F001'   ,     1  ,  'G001'   ,   1   ,   1   ,   2  union all
    select 560  ,  'F001'    ,    1  ,  'J001'   ,   2   ,   2   ,   2  
    go
    ------------------------------------------
    ------------------------------------------
    CREATE FUNCTION dbo.FUNC_AAAAA(@m_id varchar(4))
    returns @rtb TABLE
    (
    MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL,  
    MQTY int NULL,  
    DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
    DQTY int NULL,
    DPRICE int NULL,  
    DAM int NULL
    )
    AS  
    BEGIN 
    declare @tmp_tb table(
    MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
    MQTY int NULL,  
    DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
    DQTY int NULL,  
    DPRICE int NULL,  
    DAM int NULL, 
    LEV int NULL,
    TPATH varchar(200) COLLATE DATABASE_DEFAULT NULL --BOM最多是6阶的,一般都是控制在5阶之内, 200足够了
    ); 
    declare @t_id varchar(4), @t_path varchar(200), @t_lev int; insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH, LEV)
    select MGOODSID,  MQTY ,  GOODSID , QTY ,  PRICE ,  -1, (MGOODSID + '-' +GOODSID),1 from [m_bom] where mgoodsid=@m_id; declare c1 CURSOR  LOCAL FAST_FORWARD
    FOR (
    select DGOODSID,LEV,TPATH FROM @tmp_tb WHERE dam=(-1)
    );
    OPEN c1;

    FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;

    WHILE @@FETCH_STATUS = 0
    BEGIN
    insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH,LEV)
    select MGOODSID,  MQTY ,  GOODSID , QTY ,  PRICE ,  -1,(@t_path + '-' + GOODSID),(@t_lev+1) from [m_bom] where mgoodsid=@t_id;

    update @tmp_tb set DAM=0 where DGOODSID=@t_id and DAM=(-1);

    FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
    end
    CLOSE c1;
    DEALLOCATE c1; UPDATE @tmp_tb SET DAM = DQTY * DPRICE WHERE DPRICE IS NOT NULL; WHILE EXISTS(SELECT 1 FROM @tmp_tb where DPRICE is null)
    begin
    select top 1 @t_id=DGOODSID, @t_lev=LEV, @t_path=TPATH FROM @tmp_tb WHERE DPRICE is null  order by LEV DESC; UPDATE @tmp_tb set DPRICE = (select sum(a.DAM) from @tmp_tb as a where charindex(@t_path,a.tpath)=1 and a.LEV=@t_lev+1)
    where DGOODSID=@t_id and  DPRICE is null  ;

    UPDATE @tmp_tb set DAM = DQTY * DPRICE where DGOODSID=@t_id;
    end

    insert into @rtb
    select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb  ;
    --insert into @rtb
    -- select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb order by TPATH ; return;
    END
    go
    ------------------------------------------
    ------------------------------------------
    select * from dbo.FUNC_AAAAA('A001'); 
      

  4.   

    谢谢回复,本人用的是MSSQL 2000的
    insert into [M_BOM](BILLID ,MGOODSID ,MQTY , GOODSID ,ITEMNO ,QTY ,PRICE )
       declare @tmp_tb table(
                MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                MQTY int NULL,  
                DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                DQTY int NULL,  
                DPRICE int NULL
    怎么跟我原标题的不一样呢!运行脚本有如下提示:服务器: 消息 207,级别 16,状态 3,过程 FUNC_AAAAA,行 25
    列名 'MGOODSID' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 25
    列名 'MQTY' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 25
    列名 'PRICE' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 25
    列名 'MGOODSID' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 25
    列名 'mgoodsid' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 38
    列名 'MGOODSID' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 38
    列名 'MQTY' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 38
    列名 'PRICE' 无效。
    服务器: 消息 207,级别 16,状态 1,过程 FUNC_AAAAA,行 38
    列名 'mgoodsid' 无效。
      

  5.   

    还有数据MQTY,DQTY,PRICE在实际数据库里面是有小数点的,并非整数。请帮我再测试一下,谢谢!
      

  6.   


    你给出这样的数据, 难道我下面这样建表有错?
    if object_id('[M_BOM]') is not null 
    begin
        drop table [M_BOM] ;
    end
    GO
    ------------------------------------------
    ------------------------------------------
    create table [M_BOM] (BILLID int,MGOODSID varchar(4),MQTY int, GOODSID varchar(4),ITEMNO int,QTY int,PRICE int);
    go
    ------------------------------------------
    ------------------------------------------
    insert into [M_BOM](BILLID ,MGOODSID ,MQTY , GOODSID ,ITEMNO ,QTY ,PRICE )
    select 584  ,  'A001' ,       1   , 'B001'   ,   1    ,  1   ,   NULL union all  
    select 584  ,  'A001'   ,     1  ,  'C001'  ,    2  ,    2  ,    5   union all
    select 584  ,  'A001'   ,     1  ,  'D001'   ,   3  ,    1  ,    5  union all
    select 588  ,  'B001'   ,     1  ,  'E001'  ,    1   ,   1   ,   3  union all
    select 588  ,  'B001'    ,    1  ,  'F001'  ,    2   ,   2   ,   NULL  union all
    select 560  ,  'F001'   ,     1  ,  'G001'   ,   1   ,   1   ,   2  union all
    select 560  ,  'F001'    ,    1  ,  'J001'   ,   2   ,   2   ,   2  
    go
      

  7.   

    把from [m_bom] where mgoodsid=@m_id;  M_BOM 改为BOM表就能生成函数了。
    但在我的数据库里面运算如下查询却没有出现任何数据
    select * from dbo.FUNC_AAAAA('ZW2334'); 
    但我在实际查询时却有数据的,不知道为什么?
    SELECT * FROM BOM  WHERE MGOODSID='ZW2334'
    billid  mgoodsid  mqty  dgoodsid itemno  qty     price
    761 ZW2334 100.0 NC163 1 38.0 11.56
    761 ZW2334 100.0 AV5 2 6.0 10.199999999999999
    761 ZW2334 100.0 AR469 3 5.0 14.935
    761 ZW2334 100.0 NC1070 4 11.300000000000001 15.25
    761 ZW2334 100.0 NC1071 5 27.100000000000001 16.739999999999998
    761 ZW2334 100.0 NC1080 6 4.5999999999999996 29.41
    761 ZW2334 100.0 . 7 9.9999999999999995E-8 0.0
    761 ZW2334 100.0 DR024 8 6.0 12.300000000000001
    761 ZW2334 100.0 DR024 9 2.0 12.300000000000001
      

  8.   

    SELECT * FROM VBOM  这里是部分数据
    19 AV113 100.0 DR002 1 80.0 7.3500000000000005
    19 AV113 100.0 DR113 2 20.0 31.93
    20 AV114 100.0 DR002 1 79.5 7.3500000000000005
    20 AV114 100.0 DR175 2 20.0 28.84
    20 AV114 100.0 DR177 3 0.5 35.535000000000004
    66 AV612 100.0 AV267 1 40.0 10.4
    66 AV612 100.0 AR471 2 20.0 46.350000000000001
    66 AV612 100.0 AV267 3 40.0 10.4
    67 AV614 100.0 AV267 1 60.0 10.4
    67 AV614 100.0 AR423 2 20.0 42.230000000000004
    67 AV614 100.0 AV267 3 20.0 10.4
    68 AV628 100.0 DR001 1 10.0 9.240000000000002
    68 AV628 100.0 DR002 2 20.0 7.3500000000000005
    68 AV628 100.0 AR426 3 20.0 54.590000000000003
    68 AV628 100.0 AV168 4 50.0 15.68
    69 AV804 100.0 DR001 1 13.0 9.240000000000002
    69 AV804 100.0 DR002 2 30.5 7.3500000000000005
    69 AV804 100.0 DR006 3 5.2000000000000002 9.5549999999999997
    69 AV804 100.0 DR009 4 9.8000000000000007 6.1950000000000003
    69 AV804 100.0 DR017 5 6.5 6.7200000000000006
    69 AV804 100.0 DR108 6 35.0 27.810000000000002
    70 G18X1 100.0 DR002 5 25.0 7.3500000000000005
    70 G18X1 100.0 DR006 6 10.0 9.5549999999999997
    70 G18X1 100.0 DR016 7 65.0 6.8300000000000001
    71 G18X2 100.0 DR001 14 10.0 9.240000000000002
    71 G18X2 100.0 DR002 15 25.0 7.3500000000000005
    71 G18X2 100.0 DR009 16 12.0 6.1950000000000003
    71 G18X2 100.0 DR016 17 53.0 6.8300000000000001
    72 G18X3 100.0 DR001 1 28.0 9.240000000000002
    72 G18X3 100.0 DR002 2 25.0 7.3500000000000005
    72 G18X3 100.0 DR009 3 17.0 6.1950000000000003
    72 G18X3 100.0 DR016 4 30.0 6.8300000000000001
    73 G18X5 100.0 DR002 1 25.0 7.3500000000000005
    73 G18X5 100.0 DR006 2 8.0 9.5549999999999997
    73 G18X5 100.0 DR016 4 52.0 6.8300000000000001
    73 G18X5 100.0 DR019 5 15.0 10.395000000000001
    74 G18X6 100.0 DR001 1 10.0 9.240000000000002
    74 G18X6 100.0 DR002 2 25.0 7.3500000000000005
    74 G18X6 100.0 DR009 3 10.0 6.1950000000000003
    74 G18X6 100.0 DR016 4 45.0 6.8300000000000001
    74 G18X6 100.0 DR019 5 10.0 10.395000000000001
    75 G18X7 100.0 DR001 1 38.0 9.240000000000002
    75 G18X7 100.0 DR002 2 22.0 7.3500000000000005
    75 G18X7 100.0 DR009 3 15.0 6.1950000000000003
    75 G18X7 100.0 DR019 4 25.0 10.395000000000001
    76 G18X10 100.0 DR002 1 22.0 7.3500000000000005
    76 G18X10 100.0 DR006 2 10.0 9.5549999999999997
    76 G18X10 100.0 DR019 3 20.0 10.395000000000001
    76 G18X10 100.0 DR016 4 48.0 6.8300000000000001
    77 G18X12 100.0 DR002 1 10.0 7.3500000000000005
    77 G18X12 100.0 DR003 2 12.0 7.7700000000000005
    77 G18X12 100.0 DR005 3 68.0 10.709999999999999
    77 G18X12 100.0 DR006 4 10.0 9.5549999999999997
    78 G18X18 100.0 DR001 1 19.0 9.240000000000002
    78 G18X18 100.0 DR002 2 25.0 7.3500000000000005
    78 G18X18 100.0 DR006 3 6.0 9.5549999999999997
    78 G18X18 100.0 DR019 4 50.0 10.395000000000001
    79 G18X19 100.0 DR001 1 19.0 9.240000000000002
    79 G18X19 100.0 DR002 2 25.0 7.3500000000000005
    79 G18X19 100.0 DR005 3 50.0 10.709999999999999
    79 G18X19 100.0 DR009 4 6.0 6.1950000000000003
    80 G18X20 100.0 DR002 1 25.0 7.3500000000000005
    80 G18X20 100.0 DR006 2 3.0 9.5549999999999997
    80 G18X20 100.0 DR009 3 7.0 6.1950000000000003
    80 G18X20 100.0 DR019 4 65.0 10.395000000000001
    81 G18X21 100.0 DR001 1 38.0 9.240000000000002
    81 G18X21 100.0 DR002 2 22.0 7.3500000000000005
    81 G18X21 100.0 DR005 3 25.0 10.709999999999999
    81 G18X21 100.0 DR008 4 10.0 6.4050000000000002
    81 G18X21 100.0 DR009 5 5.0 6.1950000000000003
    82 NC143 100.0 DR008 1 42.0 6.4050000000000002
    82 NC143 100.0 DR009 2 25.0 6.1950000000000003
    82 NC143 100.0 NCH1/46 3 33.0 12.772
    83 GFPX1 100.0 DR002 8 17.0 7.3500000000000005
    83 GFPX1 100.0 DR016 9 63.0 6.8300000000000001
    83 GFPX1 100.0 DR019 10 20.0 10.395000000000001
    84 GFPX2 100.0 DR001 1 10.0 9.240000000000002
    84 GFPX2 100.0 DR002 2 17.0 7.3500000000000005
    84 GFPX2 100.0 DR019 3 20.0 10.395000000000001
    84 GFPX2 100.0 DR016 4 53.0 6.8300000000000001
    85 GFPX3 100.0 DR001 11 30.0 9.240000000000002
    85 GFPX3 100.0 DR002 12 17.0 7.3500000000000005
    85 GFPX3 100.0 DR016 13 53.0 6.8300000000000001
    87 GPPX1 100.0 DR001 1 10.0 9.240000000000002
    87 GPPX1 100.0 DR002 2 72.0 7.3500000000000005
    87 GPPX1 100.0 DR006 3 6.0 9.5549999999999997
    87 GPPX1 100.0 DR019 4 12.0 10.395000000000001
    88 GPPX2 100.0 DR001 1 10.0 9.240000000000002
    88 GPPX2 100.0 DR002 2 75.0 7.3500000000000005
    88 GPPX2 100.0 DR009 3 10.0 6.1950000000000003
    88 GPPX2 100.0 DR019 4 5.0 10.395000000000001
    89 GPPX3 100.0 DR001 1 30.0 9.240000000000002
    89 GPPX3 100.0 DR002 2 60.0 7.3500000000000005
    89 GPPX3 100.0 DR009 3 10.0 6.1950000000000003
    90 GPPX4 100.0 DR001 1 15.0 9.240000000000002
    90 GPPX4 100.0 DR002 2 72.0 7.3500000000000005
    90 GPPX4 100.0 DR006 3 3.0 9.5549999999999997
    90 GPPX4 100.0 DR009 4 10.0 6.1950000000000003
    91 RW101 100.0 DR008 1 40.0 6.4050000000000002
    91 RW101 100.0 DR110 2 30.0 15.450000000000001
    91 RW101 100.0 AR429 3 30.0 48.410000000000004
    92 NC163 100.0 DR001 1 40.0 9.240000000000002
    92 NC163 100.0 DR009 2 10.0 6.1950000000000003
    92 NC163 100.0 DR024 3 12.0 12.300000000000001
    92 NC163 100.0 NCH1/166 4 38.0 16.48
    93 NC163-2 100.0 DR008 1 15.0 6.4050000000000002
    93 NC163-2 100.0 DR009 2 19.5 6.1950000000000003
    93 NC163-2 100.0 DR024 3 27.0 12.300000000000001
    93 NC163-2 100.0 NCH1/166 4 38.5 16.48
      

  9.   

    各位兄台,请看这份原始数据会清楚点(有关联关系的),谢谢!!billid  mgoodsid  mqty  dgoodsid itemno  qty    price 
    92 NC163 100.0 DR001 1 40.0 9.240000000000002
    92 NC163 100.0 DR009 2 10.0 6.1950000000000003
    92 NC163 100.0 DR024 3 12.0 12.300000000000001
    92 NC163 100.0 NCH1/166 4 38.0 16.48
    137 NC163 100.0 DR001 1 40.0 9.240000000000002
    137 NC163 100.0 DR009 2 10.0 6.1950000000000003
    137 NC163 100.0 DR024 3 12.0 12.300000000000001
    137 NC163 100.0 NCH1/166 4 38.0 16.48
    736 ZW2343 100.0 NC163 1 13.0 11.56
    736 ZW2343 100.0 AV5 2 6.0 10.199999999999999
    736 ZW2343 100.0 AR469 3 5.0 14.935
    736 ZW2343 100.0 DR023 4 5.0 12.300000000000001
    736 ZW2343 100.0 NC1071 5 66.0 16.739999999999998
    736 ZW2343 100.0 . 6 9.9999999999999995E-8 0.0
    736 ZW2343 100.0 DR001 7 3.0 9.240000000000002
    736 ZW2343 100.0 DR024 8 2.0 12.300000000000001
    736 ZW2343 100.0 DR024 9 9.9999999999999995E-8 12.300000000000001
    64 AV5 100.0 DR008 1 50.0 6.4050000000000002
    64 AV5 100.0 DR110 2 50.0 15.450000000000001
    65 AV5 100.0 DR008 1 50.0 6.4050000000000002
    65 AV5 100.0 DR172 2 50.0 19.57
    755 ZW2372 100.0 NC2048 4 1.8 21.059999999999999
    755 ZW2372 100.0 NC1020 5 2.6000000000000001 15.300000000000001
    755 ZW2372 100.0 . 6 9.9999999999999995E-8 0.0
    755 ZW2372 100.0 DR023 7 5.0 12.300000000000001
    755 ZW2372 100.0 DR024 8 7.0 12.300000000000001
    755 ZW2372 100.0 DR024 9 1.6000000000000001 12.300000000000001
      

  10.   

    我是有点晕了
    要不这样吧, 你把表结构给确定下来吧, 我们都不清楚你每个字段是什么类型啊,还有是一张表还是多张表。create table [M_BOM] --  这里,你确认一下你的表名是不是M_BOM 
    (
    BILLID int,        --  这个字段没有疑问, 应该是int的
    MGOODSID varchar(4),    
    MQTY int,  --  这个字段的类型需要说清楚是什么类型, 从你的数据分析, 不是int的
    GOODSID varchar(4),
    ITEMNO int, --  这个字段的类型需要说清楚是什么类型, 从你的数据分析, 不是int的
    QTY int, --  这个字段的类型需要说清楚是什么类型, 从你的数据分析, 不是int的
    PRICE int --  这个字段的类型需要说清楚是什么类型, 从你的数据分析, 不是int的);
      

  11.   

    (1)的结果,如你所说,数据大时,速度会比较慢,但是(1)是一个总结果,
    花一些时间把它算下来,假如存到一个table里,再要求(2)不就直接select了吗?
    如果你的目的只是为了求(2),可以用展BOM的function,应该不会很慢吧?
    BOM一共多少数据?
      

  12.   


    数据多了用展开bom的function是比较慢的, 还是得用空间换时间, 尽量把数据“挤”进局部内存临时表来计算。
      

  13.   

    以前老大写了一个,不知道是否合适,
    给你参考一下,看你前面一个帖子,好像没有提到老大的这个函数,
    好像老大的BLOG上面有新的算法,不过是基于2005的.--BOM算法
    --产品配件清单查询示例(邹建)
    CREATE TABLE Item(ID int,Name varchar(10),Wast decimal(2,2))
    INSERT Item SELECT 1,N'A产品',0.01
    UNION  ALL  SELECT 2,N'B产品',0.02
    UNION  ALL  SELECT 3,N'C产品',0.10
    UNION  ALL  SELECT 4,N'D配件',0.15
    UNION  ALL  SELECT 5,N'E物料',0.03
    UNION  ALL  SELECT 6,N'F物料',0.01
    UNION  ALL  SELECT 7,N'G配件',0.02CREATE TABLE Bom(ItemID int,ChildId int)
    INSERT Bom SELECT 1,4
    UNION  ALL SELECT 1,7   --A产品由D配件和G配件组成
    UNION  ALL SELECT 2,1
    UNION  ALL SELECT 2,6
    UNION  ALL SELECT 2,7   --B产品由F物料及G配件组成
    UNION  ALL SELECT 4,5
    UNION  ALL SELECT 4,6    --D配件由F物料组成
    UNION  ALL SELECT 3,2
    UNION  ALL SELECT 3,1    --C产品由A产品和B产品组成
    GOCREATE FUNCTION f_Bom(
    @ItemIDs varchar(1000), --要查询物料清单及生产量的产品编号列表(逗号分隔)
    @Num   int          --要生产的数量
    )RETURNS @t TABLE(ItemID int,ChildId int,Nums int,Level int)
    AS
    BEGIN
        DECLARE @Level int
        SET @Level=1
        INSERT @t SELECT a.ItemID,a.ChildId,ROUND(@Num/(1-b.Wast),0),@Level
        FROM Bom a,Item b
        WHERE a.ChildId=b.ID
            AND CHARINDEX(','+RTRIM(a.ItemID)+',',','+@ItemIDs+',')>0
        WHILE @@ROWCOUNT>0 and @Level<140
        BEGIN
            SET @Level=@Level+1
            INSERT @t SELECT a.ItemID,b.ChildId,ROUND(a.Nums/(1-c.Wast),0),@Level
            FROM @t a,Bom b,Item c
            WHERE a.ChildId=b.ItemID
                AND b.ChildId=c.ID
                AND a.Level=@Level-1
        END
        RETURN
    END
    GO--调用函数展开产品1、2、3的结构及计算生产10个产品时,各需要多少个配件
    SELECT a.ItemID,ItemName=b.Name,
        a.ChildId,ChildName=c.Name,
        a.Nums,a.Level
    FROM f_Bom('1,2,3',10) a,Item b,Item c
    WHERE a.ItemID=b.ID
        AND a.ChildId=c.ID
    ORDER BY a.ItemID,a.Level,a.ChildId/*
    ItemID      ItemName   ChildId     ChildName  Nums        Level
    ----------- ---------- ----------- ---------- ----------- -----------
    1           A产品        4           D配件        12          1
    1           A产品        7           G配件        10          1
    1           A产品        5           E物料        12          2
    1           A产品        6           F物料        12          2
    2           B产品        1           A产品        10          1
    2           B产品        6           F物料        10          1
    2           B产品        7           G配件        10          1
    2           B产品        4           D配件        12          2
    2           B产品        7           G配件        10          2
    2           B产品        5           E物料        12          3
    2           B产品        6           F物料        12          3
    3           C产品        1           A产品        10          1
    3           C产品        2           B产品        10          1
    3           C产品        1           A产品        10          2
    3           C产品        4           D配件        12          2
    3           C产品        6           F物料        10          2
    3           C产品        7           G配件        10          2
    3           C产品        7           G配件        10          2
    3           C产品        4           D配件        12          3
    3           C产品        5           E物料        12          3
    3           C产品        6           F物料        12          3
    3           C产品        7           G配件        10          3
    3           C产品        5           E物料        12          4
    3           C产品        6           F物料        12          4(24 row(s) affected)
    */
    drop table item
    drop table bom
    drop function f_Bom
      

  14.   

    如果针对单个料号的,上述function应该是够用的了
    但是如果针对多个料号(比如所有的成品料号)
    我直接写过一个用临时表展BOM的方式,
    如下是根据这个需求改过的,具体思路可参考,至少我用这种方式展50w资料的bom,针对约1w颗成品料一起展,约30秒不到
    create table bom(billid int, p_id varchar(10), pqty int, c_id varchar(10), 
                     itemno int, cqty int, dprice int)
    insert into bom
              select 584,'A001',1,'B001',1,1,null
    union all select 584,'A001',1,'C001',2,2,5
    union all select 584,'A001',1,'D001',3,1,5
    union all select 588,'B001',1,'E001',1,1,3
    union all select 588,'B001',1,'F001',2,2,null
    union all select 560,'F001',1,'G001',1,1,2
    union all select 560,'F001',1,'J001',2,2,null
    union all select 560,'J001',1,'L001',1,3,4
    union all select 560,'J001',1,'M001',2,1,5
    union all select 560,'J001',1,'N001',2,1,3
    GO
    Create proc dbo.usp_bom
    @p_id varchar(10)
    AS
    declare @loop int
    set @loop=1
    select p_id, pqty, c_id as tmp_id, c_id, cqty as tmp_qty,cqty,dprice, DAM=cqty*isnull(dprice,0)
    into #bom
    from bom
    where p_id=@p_id  --这边的where只是举例子,如抓的是多颗料,也是一样展开while (@loop>0)
    BEGIN
      select #bom.p_id,#bom.c_id as tmp_id, bom.c_id,bom.cqty,
      DAM=sum(#bom.cqty*#bom.tmp_qty*(#bom.DAM+bom.cqty*isnull(bom.dprice,0)))
      into #temp_bom
      from #bom, bom
      where #bom.c_id=bom.p_id
      group by #bom.p_id,#bom.c_id , bom.c_id,bom.cqty 
      select #bom.p_id,#bom.pqty,#bom.tmp_id, #temp_bom.c_id,#bom.cqty as tmp_cqty,#temp_bom.cqty,#bom.dprice,#temp_bom.DAM
      into #insert
       from #bom,#temp_bom
      where #bom.p_id=#temp_bom.p_id and #bom.c_id=#temp_bom.tmp_id  delete #bom
      from #bom, #temp_bom
      where #bom.c_id=#temp_bom.tmp_id set @loop=@@rowcount    insert into #bom select * from #insert   drop table #temp_bom, #insert
       
    END
    --result
    select #bom.p_id,#bom.pqty,#bom.tmp_id,
           bom.cqty, sum(isnull(#bom.dprice,#bom.DAM)) as dprice,sum(#bom.DAM) as DAM
     from #bom,bom
     where #bom.p_id=bom.p_id and #bom.tmp_id=bom.c_id
     group by #bom.p_id,#bom.pqty,#bom.tmp_id, bom.cqty
    GOexec dbo.usp_bom 'A001'
    /*
    p_id       pqty        tmp_id     cqty        dprice      DAM
    ---------- ----------- ---------- ----------- ----------- -----------
    A001       1           B001       1           87          87
    A001       1           C001       2           5           10
    A001       1           D001       1           5           5
    */
    GOdrop table bom
    drop proc dbo.usp_bom
      

  15.   

    本来是两张主、从表的 主表M_BOM ,细表M_BOMD ,我用视图把这两张表并在一起
    变成了一个视图 BOM
    SQL codecreatetable[M_BOM]--  这里,确认表名是BOM
    BILLID int,-- 
    MQTY FLOAT 
    GOODSID varchar(4),
    ITEMNO  int,-- 
    QTY FLOAT,--  
    PRICE  FLOAT--  不好意思说得不清楚!!
      

  16.   


    把主表的结构也给出来吧, 你上面说的这个是分表的, 还有描述清楚主表跟分表是怎么关联的。
    还有个问题, 见下面billid  mgoodsid  mqty  dgoodsid itemno  qty    price
    92 NC163 100.0 DR001 1 40.0 9.240000000000002 其中的price是什么值的时候表示该值是由它的下一级来计算的, 是null还是0?
      

  17.   

    --1.
    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2))
    Insert BOM
    Select 584,'A001',1.00,'B001',1.00,1.00,null union all
    Select 584,'A001',1,'C001',2,2,5.00 union all
    Select 584,'A001',1,'D001',3,1,5 union all
    Select 588,'B001',1,'E001',1,1,3 union all
    Select 588,'B001',1,'F001',2,2,null union all
    Select 560,'F001',1,'G001',1,1,2 union all
    Select 560,'F001',1,'J001',2,2,2
    Go
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
    Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
    declare @lvl int
    set @lvl=0
    insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
    begin
    set @lvl=@lvl+1
    insert @t 
    select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
    from BOM a,@t b
    where a.MGoodsID=b.DGoodsID 
    and b.lvl=@lvl-1
            end
    declare @i int
    select @i=max(lvl) from @t where dprice is null
    while @i>=0
    begin
    update a set 
    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID),
    damt=dqty*(select sum(damt) from @t where a.DGOODSID=MGOODSID)
    from @t a
    where lvl=@i
    and dprice is null
        set @i=@i-1
    end
    update @t set DAMT=DQTY*DPRICE where DAMT is null
    return
    end
    go
    select * from fn_bom('a001') 
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 1.00                                    B001                 1.00                                    1.00                                    15.00                                   15.00                                   0
    A001                 1.00                                    C001                 2.00                                    2.00                                    5.00                                    10.00                                   0
    A001                 1.00                                    D001                 3.00                                    1.00                                    5.00                                    5.00                                    0
    B001                 1.00                                    E001                 1.00                                    1.00                                    3.00                                    3.00                                    1
    B001                 1.00                                    F001                 2.00                                    2.00                                    6.00                                    12.00                                   1
    F001                 1.00                                    G001                 1.00                                    1.00                                    2.00                                    2.00                                    2
    F001                 1.00                                    J001                 2.00                                    2.00                                    2.00                                    4.00                                    2(7 行受影响)*/
      

  18.   

    --2.
    select * from fn_bom('a001') where mgoodsid='a001'
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 1.00                                    B001                 1.00                                    1.00                                    15.00                                   15.00                                   0
    A001                 1.00                                    C001                 2.00                                    2.00                                    5.00                                    10.00                                   0
    A001                 1.00                                    D001                 3.00                                    1.00                                    5.00                                    5.00                                    0(3 行受影响)*/
      

  19.   

    playwarcraft兄你们,谢谢你的帮助,查询在5秒内了,哈哈!!
    运行:
    A001*1  ----B001*1  C001*1   D001*1  
    B001*1  ----E001*1  F001*1
    F001*1  ----G001*1  J001*1
    exec dbo.usp_bom 'A001'   ---我这里计算是100个A001
    (注意G001/J001/E001/C001/D001 测试时均把单价改为1 ,上下阶数量是1:1)
    结果如下:
    A001 100.0 B001 100.0 3.0 40004000000.0
    A001 100.0 C001 100.0 1.0 100.0
    A001 100.0 D001 100.0 1.0 100.040004000000.0这个不知道是怎么回事
    100*3=300才对呀?
      

  20.   

    试试我的, 创建时候有什么错误提示, 贴商量, 跟楼上哥们一样, 今天比较“宅”
    CREATE FUNCTION dbo.FUNC_AAAAA(@m_id varchar(4))
    returns @rtb TABLE
    (
        MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL,  
        MQTY float NULL,  
        DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
        DQTY float NULL,
        DPRICE float NULL,  
        DAM float NULL
    )
    AS  
    BEGIN 
        declare @tmp_tb table(
                MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                MQTY float NULL,  
                DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                DQTY float NULL,  
                DPRICE float NULL,  
                DAM float NULL, 
                LEV int NULL,
                TPATH varchar(200) COLLATE DATABASE_DEFAULT NULL --BOM最多是6阶的,一般都是控制在5阶之内, 200足够了
        ); 
        declare @t_id varchar(4), @t_path varchar(200), @t_lev int;    insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH, LEV)
            select MGOODSID,  MQTY ,  GOODSID , QTY ,  PRICE ,  -1, (MGOODSID + '-' +GOODSID),1 from [bom] where mgoodsid=@m_id;    declare c1 CURSOR  LOCAL FAST_FORWARD
            FOR (
                select DGOODSID,LEV,TPATH FROM @tmp_tb WHERE dam=(-1)
            );
        OPEN c1;
        
        FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
        
        WHILE @@FETCH_STATUS = 0
        BEGIN
            insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH,LEV)
                select MGOODSID,  MQTY ,  GOODSID , QTY ,  PRICE ,  -1,(@t_path + '-' + GOODSID),(@t_lev+1) from [bom] where mgoodsid=@t_id;
                
            update @tmp_tb set DAM=0 where DGOODSID=@t_id and DAM=(-1);
            
            FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
        end
        CLOSE c1;
        DEALLOCATE c1;    UPDATE @tmp_tb SET DAM = DQTY * DPRICE WHERE DPRICE IS NOT NULL;    WHILE EXISTS(SELECT 1 FROM @tmp_tb where DPRICE is null)
        begin
            select top 1 @t_id=DGOODSID, @t_lev=LEV, @t_path=TPATH FROM @tmp_tb WHERE DPRICE is null  order by LEV DESC;        UPDATE @tmp_tb set DPRICE = (select sum(a.DAM) from @tmp_tb as a where charindex(@t_path,a.tpath)=1 and a.LEV=@t_lev+1)
                    where DGOODSID=@t_id and  DPRICE is null  ;
                    
            UPDATE @tmp_tb set DAM = DQTY * DPRICE where DGOODSID=@t_id;
        end
        
        insert into @rtb
                select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb  ;
        --insert into @rtb
        --        select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb order by TPATH ;    return;
    END
    go
    ------------------------------------------
    ------------------------------------------
    select * from dbo.FUNC_AAAAA('A001'); 
      

  21.   

    htl258兄,谢谢你的帮忙,速度也在5秒之内,
    我想要的结果是计算成本单价  (B001=E001+G001+J001)今天星期天都在家测试,谢谢大家!
      

  22.   

    --用我上面的函数:--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
    Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,sum(MQTY) MQTY,sum(DAMT) DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    group by MGOODSID
    GO
    --调用过程
    [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    B001                 2.00                                    15.00(1 行受影响)
    */
    [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    A001                 3.00                                    30.00(1 行受影响)
    */
      

  23.   

    谢谢,希望能继续改进一下,跟我想要的A001的成本单价有点出入.(B001=E001+G001+J001),
    以下是在我实际数据库里面的测试,可以跟原题目有点出入.
    select * from dbo.FUNC_AAAAA('A001'); 
    A001 100.0 B001 100.0 1.0 100.0
    A001 100.0 C001 100.0 1.0 100.0
    A001 100.0 D001 100.0 1.0 100.0
    B001 100.0 E001 100.0 1.0 100.0
    B001 100.0 F001 100.0 1.0 100.0
    F001 100.0 G001 100.0 1.0 100.0
    F001 100.0 J001 100.0 1.0 100.0要求出的结果如下:
    实际数据库中
    A001*1  ----B001*1  C001*1  D001*1  
    B001*1  ----E001*1  F001*1 
    F001*1  ----G001*1  J001*1 
     ---我这里计算是100个A001 
    (注意G001/J001/E001/C001/D001 测试时均把单价改为1 ,上下阶数量是1:1) 
    select * from dbo.FUNC_AAAAA('A001'); 
    A001 100.0 B001 100.0 3 300
    A001 100.0 C001 100.0 1.0 100.0
    A001 100.0 D001 100.0 1.0 100.0
      

  24.   


    以下运行
    [Sp_BOM] 'a001'A001 300.00 300.00[Sp_BOM] 'b001'
    B001 200.00 200.00A001*1  ----B001*1  C001*1  D001*1  
    B001*1  ----E001*1  F001*1 
    F001*1  ----G001*1  J001*1 
       G001、J001、E001、C001、D001单价均为1时
    ---我这里计算是100个A001 ,100个B001
    A001  应该是500才对
    B001  应该是300才对
      

  25.   

    再说一下我的数据库里面的测试环境,跟原题目有点出入,我贴出来的结果是我数据库里面的数据                             A001  100KG
               |                   |             |
         B001 100KG               C001 100KG       D001 100KG
              |         |
      E001 100KG    F001 100KG      
                          |      |
                  G001 100KG  J001 100KG G001、J001、E001、C001、D001 单价都是1元/KG,作测试的。
      

  26.   


    谢谢,希望能继续改进一下,跟我想要的A001的成本单价有点出入.(B001=E001+G001+J001), 
    以下是运行你的脚本执行结果 
    select * from dbo.FUNC_AAAAA('A001'); 
    A001 100.0 B001 100.0 1.0 100.0 
    A001 100.0 C001 100.0 1.0 100.0 
    A001 100.0 D001 100.0 1.0 100.0 
    B001 100.0 E001 100.0 1.0 100.0 
    B001 100.0 F001 100.0 1.0 100.0  
    F001 100.0 G001 100.0 1.0 100.0 
    F001 100.0 J001 100.0 1.0 100.0 要求出的正确结果如下: 
    select * from dbo.FUNC_AAAAA('A001'); 
    A001 100.0 B001 100.0 3 300   ----------就是这里有点 B001=E001+G001+J001
    A001 100.0 C001 100.0 1.0 100.0 
    A001 100.0 D001 100.0 1.0 100.0 
      

  27.   

    B001数量=100KG
    B001成本价=GOO1成本价+J001成本价+E001成本价
              =100*1 + 100 *1  + 100*1
             =300元
      

  28.   


    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2))
    Insert BOM
    Select 584,'A001',100.00,'B001',1.00,100.00,null union all
    Select 584,'A001',100,'C001',2,100,1.00 union all
    Select 584,'A001',100,'D001',3,100,1 union all
    Select 588,'B001',100,'E001',1,100,1 union all
    Select 588,'B001',100,'F001',2,100,null union all
    Select 560,'F001',100,'G001',1,100,1 union all
    Select 560,'F001',100,'J001',2,100,1
    Go
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t where dprice is null
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(dprice) from @t where a.DGOODSID=MGOODSID),
                    damt=dqty*(select sum(dprice) from @t where a.DGOODSID=MGOODSID)
                from @t a
                where lvl=@i
                    and dprice is null
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 100.00                                  B001                 1.00                                    100.00                                  3.00                                    300.00                                  0
    A001                 100.00                                  C001                 2.00                                    100.00                                  1.00                                    100.00                                  0
    A001                 100.00                                  D001                 3.00                                    100.00                                  1.00                                    100.00                                  0
    B001                 100.00                                  E001                 1.00                                    100.00                                  1.00                                    100.00                                  1
    B001                 100.00                                  F001                 2.00                                    100.00                                  2.00                                    200.00                                  1
    F001                 100.00                                  G001                 1.00                                    100.00                                  1.00                                    100.00                                  2
    F001                 100.00                                  J001                 2.00                                    100.00                                  1.00                                    100.00                                  2(7 行受影响)*/改下函数就行了。
      

  29.   

    其它查询均不变:
    --计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,sum(MQTY) MQTY,sum(DAMT) DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    group by MGOODSID
    GO
    --调用过程
    [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    B001                 200.00                                  300.00(1 行受影响)*/
    [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    A001                 300.00                                  500.00(1 行受影响)
    */
      

  30.   

    差不多了,
    但是MQTY为什么会变了其它数量了,应该为原来的100数量,
    怎么没有单价PRICE?  数量*单价才=金额  
      

  31.   


    --来个比较完整的。
    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2))
    Insert BOM
    Select 584,'A001',100.00,'B001',1.00,100.00,null union all
    Select 584,'A001',100,'C001',2,100,1.00 union all
    Select 584,'A001',100,'D001',3,100,1 union all
    Select 588,'B001',100,'E001',1,100,1 union all
    Select 588,'B001',100,'F001',2,100,null union all
    Select 560,'F001',100,'G001',1,200,1 union all
    Select 560,'F001',100,'J001',2,100,2
    Go
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t where dprice is null
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/dqty,
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)
                from @t a
                where lvl=@i
                    and dprice is null
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 100.00                                  B001                 1.00                                    100.00                                  5.00                                    500.00                                  0
    A001                 100.00                                  C001                 2.00                                    100.00                                  1.00                                    100.00                                  0
    A001                 100.00                                  D001                 3.00                                    100.00                                  1.00                                    100.00                                  0
    B001                 100.00                                  E001                 1.00                                    100.00                                  1.00                                    100.00                                  1
    B001                 100.00                                  F001                 2.00                                    100.00                                  4.00                                    400.00                                  1
    F001                 100.00                                  G001                 1.00                                    200.00                                  1.00                                    200.00                                  2
    F001                 100.00                                  J001                 2.00                                    100.00                                  2.00                                    200.00                                  2(7 行受影响)*/--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,sum(MQTY) MQTY,sum(DAMT) DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    group by MGOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    B001                 200.00                                  500.00(1 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    A001                 300.00                                  700.00(1 行受影响)
    */
      

  32.   

    MQTY为原来数量,过程小改一下就行了:
    --计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,sum(DAMT) DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    group by MGOODSID,MQTY
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  500.00(1 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  700.00(1 行受影响)
    */
      

  33.   

    htl258兄把数据按如下重新导入 (以下是实际数据)   DRPICE半成品或成本的单价为0.0 非NULL
    现帮我测试一下,谢谢!!  
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2))
    Insert BOM
    Select 584,'A001',100.00,'B001',1.00,100.00,0.0 union all
    Select 584,'A001',100.00,'C001',2,100,1.00 0.0 all
    Select 584,'A001',100.00,'D001',3,100,1 union all
    Select 588,'B001',100.00,'E001',1,100,1 union all
    Select 588,'B001',100.00,'F001',2,100,0.0 union all
    Select 560,'F001',100.00,'G001',1,100,1 union all
    Select 560,'F001',100.00,'J001',2,100,1
    Go录入相关数据后再执行,结果发现数量和金额有出入。
    exec [Sp_BOM] 'B001'
    B001 200.00 200.00exec [Sp_BOM] 'A001'
    A001 300.00 300.00先休息一会吧,多谢你!
      

  34.   


    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2)) 
    Insert BOM 
    Select 584,'A001',100.00,'B001',1.00,100.00,0.0 union all 
    Select 584,'A001',100.00,'C001',2,100,1.00 union all 
    Select 584,'A001',100.00,'D001',3,100,1 union all 
    Select 588,'B001',100.00,'E001',1,100,1 union all 
    Select 588,'B001',100.00,'F001',2,100,0.0 union all 
    Select 560,'F001',100.00,'G001',1,100,1 union all 
    Select 560,'F001',100.00,'J001',2,100,1 
    Go 
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t where dprice =0
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/dqty,
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)
                from @t a
                where lvl=@i
                    and dprice =0
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 100.00                                  B001                 1.00                                    100.00                                  3.00                                    300.00                                  0
    A001                 100.00                                  C001                 2.00                                    100.00                                  1.00                                    100.00                                  0
    A001                 100.00                                  D001                 3.00                                    100.00                                  1.00                                    100.00                                  0
    B001                 100.00                                  E001                 1.00                                    100.00                                  1.00                                    100.00                                  1
    B001                 100.00                                  F001                 2.00                                    100.00                                  2.00                                    200.00                                  1
    F001                 100.00                                  G001                 1.00                                    100.00                                  1.00                                    100.00                                  2
    F001                 100.00                                  J001                 2.00                                    100.00                                  1.00                                    100.00                                  2(7 行受影响)
    */--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,sum(DAMT) DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    group by MGOODSID,MQTY
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  300.00(1 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  500.00(1 行受影响)
    */
      

  35.   

    htl258兄, exec [Sp_BOM] 'A001'如果查询的时候能这样出来的效果就会更好些,比较清晰些。
    MGOODIS MQTY DGOODSID DQTY DPRICE DAM
    A001 100.0 B001 100.0 3 300  
    A001 100.0 C001 100.0 1.0 100.0 
    A001 100.0 D001 100.0 1.0 100.0 
      

  36.   

    --计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  100.00
    B001                 100.00                                  200.00(2 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DAMT
    -------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  300.00
    A001                 100.00                                  100.00
    A001                 100.00                                  100.00(3 行受影响)
    */
      

  37.   

    sorry,没仔细看:
    --计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,DGOODSID ,DQTY,DPRICE,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  E001                 100.00                                  1.00                                    100.00
    B001                 100.00                                  F001                 100.00                                  2.00                                    200.00(2 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  B001                 100.00                                  3.00                                    300.00
    A001                 100.00                                  C001                 100.00                                  1.00                                    100.00
    A001                 100.00                                  D001                 100.00                                  1.00                                    100.00(3 行受影响)
    */
      

  38.   

    早这样给表结构和样本数据早解决了
    CREATE FUNCTION dbo.FUNC_AAAAA(@m_id varchar(4))
    returns @rtb TABLE
    (
        MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL,  
        MQTY decimal(18,2) NULL,  
        DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
        DQTY decimal(18,2) NULL,
        DPRICE decimal(18,2) NULL,  
        DAM decimal(18,2) NULL
    )
    AS  
    BEGIN 
        declare @tmp_tb table(
                MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                MQTY decimal(18,2) NULL,  
                DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                DQTY decimal(18,2) NULL,  
                DPRICE decimal(18,2) NULL,  
                DAM decimal(18,2) NULL, 
                LEV int NULL,
                TPATH varchar(200) COLLATE DATABASE_DEFAULT NULL --BOM最多是6阶的,一般都是控制在5阶之内, 200足够了
        ); 
        declare @t_id varchar(4), @t_path varchar(200), @t_lev int;    insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH, LEV)
            select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  -1, (MGOODSID + '-' +DGOODSID),1 from [bom] where mgoodsid=@m_id;    declare c1 CURSOR  LOCAL FAST_FORWARD
            FOR (
                select DGOODSID,LEV,TPATH FROM @tmp_tb WHERE dam=(-1)
            );
        OPEN c1;
        
        FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
        
        WHILE @@FETCH_STATUS = 0
        BEGIN
            insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH,LEV)
                select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  -1,(@t_path + '-' + DGOODSID),(@t_lev+1) from [bom] where mgoodsid=@t_id;
                
            update @tmp_tb set DAM=0 where DGOODSID=@t_id and DAM=(-1);
            
            FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
        end
        CLOSE c1;
        DEALLOCATE c1;    UPDATE @tmp_tb SET DAM = DQTY * DPRICE WHERE DPRICE<>0;    WHILE EXISTS(SELECT 1 FROM @tmp_tb where DPRICE =0)
        begin
            select top 1 @t_id=DGOODSID, @t_lev=LEV, @t_path=TPATH FROM @tmp_tb WHERE DPRICE =0  order by LEV DESC;        UPDATE @tmp_tb set DPRICE = (select sum(a.DAM) from @tmp_tb as a where charindex(@t_path,a.tpath)=1 and a.LEV=@t_lev+1)
                    where DGOODSID=@t_id and  DPRICE = 0  ;
                    
            UPDATE @tmp_tb set DAM = DQTY * DPRICE where DGOODSID=@t_id;
        end
        
        insert into @rtb
                select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb  ;
        --insert into @rtb
        --        select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb order by TPATH ;    return;
    END
    go
    ------------------------------------------
    ------------------------------------------
    select * from dbo.FUNC_AAAAA('A001'); A001 100.00 B001 100.00 20100.00 2010000.00
    A001 100.00 C001 100.00 1.00 100.00
    A001 100.00 D001 100.00 1.00 100.00
    B001 100.00 E001 100.00 1.00 100.00
    B001 100.00 F001 100.00 200.00 20000.00
    F001 100.00 G001 100.00 1.00 100.00
    F001 100.00 J001 100.00 1.00 100.00
      

  39.   

    同时弄了个调试版本的, 不过是上一个结构的,一块发给你,  或许对你理解有帮助
    /*
    以你提供的数据为例子:
    BOM表
            产品    产品数量  原料          原料数  单价
    BILLID  MGOODSID  MQTY  DGOODSID ITEMNO  DQTY  DPRICE
    584    A001        1    B001      1      1      ??  (半成品)   
    584    A001        1    C001      2      2      5    (原料)    2个C001组成
    584    A001        1    D001      3      1      5  (原料)
    588    B001        1    E001      1      1      3    (原料)
    588    B001        1    F001      2      2      ??    (半成品)  2个F001组成
    560    F001        1    G001      1      1      2  (原料)
    560    F001        1    J001      2      2      2  (原料)    2个J001组成 */
    declare @m_id varchar(4);
    set @m_id = 'A001';    declare @tmp_tb table(
                MGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                MQTY float NULL,  
                DGOODSID varchar(4) COLLATE DATABASE_DEFAULT NULL, 
                DQTY float NULL,  
                DPRICE float NULL,  
                DAM float NULL, 
                LEV int NULL,
                TPATH varchar(200) COLLATE DATABASE_DEFAULT NULL --BOM最多是6阶的,一般都是控制在5阶之内, 200足够了
        ); 
        declare @t_id varchar(4), @t_path varchar(200), @t_lev int;    insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH, LEV)
            select MGOODSID,  MQTY ,  GOODSID , QTY ,  PRICE ,  -1, (MGOODSID + '-' +GOODSID),1 from [m_bom] where mgoodsid=@m_id;
        
        
        /*
        这一步,执行select * from  @tmp_tb; 把数据打出来,此时数据应该是
    A001 1 B001 1 NULL -1 1 A001-B001
    A001 1 C001 2 5 -1 1 A001-C001
    A001 1 D001 1 5 -1 1 A001-D001
        DAM=(-1)的记录是需要向下检索子结点的
        */
        
        
        declare c1 CURSOR  LOCAL FAST_FORWARD
            FOR (
                select DGOODSID,LEV,TPATH FROM @tmp_tb WHERE dam=(-1)
            );
        OPEN c1;
        
        FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
        
        WHILE @@FETCH_STATUS = 0
        BEGIN
            insert into @tmp_tb(MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM, TPATH,LEV)
                select MGOODSID,  MQTY ,  GOODSID , QTY ,  PRICE ,  -1,(@t_path + '-' + GOODSID),(@t_lev+1) from [m_bom] where mgoodsid=@t_id;
             /*
         这一步,以第一次循环@t_id='B001'为例子, 是把它的子结点检索出来,添加进入@tmp_tb, 这里进行了2个出来,路径和所在树的层的确定。
         数据应该是下面的
    A001 1 B001 1 NULL -1 1 A001-B001
    A001 1 C001 2 5 -1 1 A001-C001
    A001 1 D001 1 5 -1 1 A001-D001
    B001 1 E001 1 3 -1 2 A001-B001-E001
    B001 1 F001 2 NULL -1 2 A001-B001-F001
    这样B001的子结点就被加载到内存表了, 它们是否有字节点,这一步不用关, 等游标检索到它们的时候再处理
         */
            update @tmp_tb set DAM=0 where DGOODSID=@t_id and DAM=(-1);
            /*
         这一步,@t_id='B001'已经进行过检索下一级的结点操作了, 下次不需要出现在游标中了, 把它的状态置为0
         此时的数据为
    A001 1 B001 1 NULL 0 1 A001-B001
    A001 1 C001 2 5 -1 1 A001-C001
    A001 1 D001 1 5 -1 1 A001-D001
    B001 1 E001 1 3 -1 2 A001-B001-E001
    B001 1 F001 2 NULL -1 2 A001-B001-F001
    这样B001的子结点就被加载到内存表了, 它们是否有字节点,这一步不用关, 等游标检索到它们的时候再处理。
         */
            
            FETCH NEXT FROM c1 INTO @t_id,@t_lev,@t_path ;
        end
        CLOSE c1;
        DEALLOCATE c1;
        /*
         执行到这一步,@t_id='A001'下面所有的子结点, 包括字节点的子结点, 统统应该都被加载到@tmp_tb里面
         此时的数据为
    A001 1 B001 1 NULL 0 1 A001-B001
    A001 1 C001 2 5 0 1 A001-C001
    A001 1 D001 1 5 0 1 A001-D001
    B001 1 E001 1 3 0 2 A001-B001-E001
    B001 1 F001 2 NULL 0 2 A001-B001-F001
    F001 1 G001 1 2 0 3 A001-B001-F001-G001
    F001 1 J001 2 2 0 3 A001-B001-F001-J001
        */    UPDATE @tmp_tb SET DAM = DQTY * DPRICE WHERE DPRICE IS NOT NULL;
         /*
         这一步,是将所以price不是null的视为最基础的结点(注意是dprice=null, 如果不是null, 就要改成其他的条件) 计算它们。
         从你提供的数据, 我觉得我分析的没错, 如计算方法有误, 请说明白,改改
         此时的数据为
    A001 1 B001 1 NULL 0 1 A001-B001
    A001 1 C001 2 5 10 1 A001-C001
    A001 1 D001 1 5 5 1 A001-D001
    B001 1 E001 1 3 3 2 A001-B001-E001
    B001 1 F001 2 NULL 0 2 A001-B001-F001
    F001 1 G001 1 2 2 3 A001-B001-F001-G001
    F001 1 J001 2 2 4 3 A001-B001-F001-J001

    这样, 我们就可以从最底层往上面计算了
        */    WHILE EXISTS(SELECT 1 FROM @tmp_tb where DPRICE is null)
        begin
            select top 1 @t_id=DGOODSID, @t_lev=LEV, @t_path=TPATH FROM @tmp_tb WHERE DPRICE is null  order by LEV DESC;
             /*
         这一步,是确定最底层的需要计算的结点, 也就是price是NULL的,  样本数据中, 第一次选取的应该是@t_id='F001'。
         */        UPDATE @tmp_tb set DPRICE = (select sum(a.DAM) from @tmp_tb as a where charindex(@t_path,a.tpath)=1 and a.LEV=@t_lev+1)
                    where DGOODSID=@t_id and  DPRICE is null  ;
            /*
         根据上一步确定的@t_id, 计算单价, 从提供的样本数据分析, 计算公式是(price=下一级子结点DAM的和)
         不知道理解是不是对了, 如果不对, 改改
         以@t_id='F001', 为例子, 它的单价应该是 G001的dam + J001的dam
         */
                    
            UPDATE @tmp_tb set DAM = DQTY * DPRICE where DGOODSID=@t_id;
            /*
         上一步计算好单价, 这一步乘以数量计算总价
         不知道理解是不是对了, 如果不对, 改改
         */
        end
         /*
         这一步,处理完成了
         此时的数据为
    A001 1 B001 1 15 15 1 A001-B001
    A001 1 C001 2 5 10 1 A001-C001
    A001 1 D001 1 5 5 1 A001-D001
    B001 1 E001 1 3 3 2 A001-B001-E001
    B001 1 F001 2 6 12 2 A001-B001-F001
    F001 1 G001 1 2 2 3 A001-B001-F001-G001
    F001 1 J001 2 2 4 3 A001-B001-F001-J001
        */
        
        --insert into @rtb
        --        select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb  ;
        --insert into @rtb
        --        select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb order by TPATH ;
        
        select MGOODSID,  MQTY ,  DGOODSID , DQTY ,  DPRICE ,  DAM from @tmp_tb  ;
        /*
         这一步,提取需要返回的数据
         此时的数据为
    A001 1 B001 1 15 15
    A001 1 C001 2 5 10
    A001 1 D001 1 5 5
    B001 1 E001 1 3 3
    B001 1 F001 2 6 12
    F001 1 G001 1 2 2
    F001 1 J001 2 2 4
        */
    go
    ------------------------------------------
    ------------------------------------------
      

  40.   


    playwarcraft兄在吗?这里能不能再帮忙处理一下,这个方法也不错呀!
    p_id       pqty        tmp_id     cqty        dprice      DAM
    ---------- ----------- ---------- ----------- ----------- -----------
    A001       1           B001       1           87          87   -----这里不正确呀!
    A001       1           C001       2           5           10
    A001       1           D001       1           5           5*/GOdroptable bomdropproc 
      

  41.   

    我做过一个把bom记录转为bom树的javascript脚本的delphi程序,每天凌晨自动执行一次
    白天使用这个bom树页面,是非常快,只是信息相当于最多滞后一天
      

  42.   

    htl258兄你久等了。在测试中按所给的数据是可以的了。
    但还有个事情希望能防止漏洞出现。
    如果货品B001在DPRICE字段里不是0的,或修改过该货品时,
    计算时就会有问题。
    同理F001也是如此。不信的话可以在F001或B001原始资料资料中的DPRICE字段填入某个数字,就会导致计算不正确。
    SQL code
    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
        Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2)) 
    Insert BOM 
    Select 584,'A001',100.00,'B001',1.00,100.00,0.0 union all 
    Select 584,'A001',100.00,'C001',2,100,1.00 union all 
    Select 584,'A001',100.00,'D001',3,100,1 union all 
    Select 588,'B001',100.00,'E001',1,100,1 union all 
    Select 588,'B001',100.00,'F001',2,100,0.0 union all 
    Select 560,'F001',100.00,'G001',1,100,1 union all 
    Select 560,'F001',100.00,'J001',2,100,1 
    Go 
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t where dprice =0
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/dqty,
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)
                from @t a
                where lvl=@i
                    and dprice =0
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 100.00                                  B001                 1.00                                    100.00                                  3.00                                    300.00                                  0
    A001                 100.00                                  C001                 2.00                                    100.00                                  1.00                                    100.00                                  0
    A001                 100.00                                  D001                 3.00                                    100.00                                  1.00                                    100.00                                  0
    B001                 100.00                                  E001                 1.00                                    100.00                                  1.00                                    100.00                                  1
    B001                 100.00                                  F001                 2.00                                    100.00                                  2.00                                    200.00                                  1
    F001                 100.00                                  G001                 1.00                                    100.00                                  1.00                                    100.00                                  2
    F001                 100.00                                  J001                 2.00                                    100.00                                  1.00                                    100.00                                  2(7 行受影响)
    */
    SQL code--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,DGOODSID ,DQTY,DPRICE,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  E001                 100.00                                  1.00                                    100.00
    B001                 100.00                                  F001                 100.00                                  2.00                                    200.00(2 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  B001                 100.00                                  3.00                                    300.00
    A001                 100.00                                  C001                 100.00                                  1.00                                    100.00
    A001                 100.00                                  D001                 100.00                                  1.00                                    100.00(3 行受影响)
    */请测试:
    Insert BOM 
    Select 584,'A001',100.00,'B001',1.00,100.00,1 union all 
    Select 584,'A001',100.00,'C001',2,100,1.00 union all 
    Select 584,'A001',100.00,'D001',3,100,1 union all 
    Select 588,'B001',100.00,'E001',1,100,1 union all 
    Select 588,'B001',100.00,'F001',2,100,1 union all 
    Select 560,'F001',100.00,'G001',1,100,1 union all 
    Select 560,'F001',100.00,'J001',2,100,1 
      

  43.   


    ---------------------------------
    --  Author: htl258(Tony)
    --  Date  : 2009-08-29 16:57:24
    ---------------------------------
    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2)) 
    Insert BOM 
    Select 584,'A001',100.00,'B001',1.00,100.00,1 union all 
    Select 584,'A001',100.00,'C001',2,100,1.00 union all 
    Select 584,'A001',100.00,'D001',3,100,1 union all 
    Select 588,'B001',100.00,'E001',1,100,1 union all 
    Select 588,'B001',100.00,'F001',2,100,1 union all 
    Select 560,'F001',100.00,'G001',1,100,1 union all 
    Select 560,'F001',100.00,'J001',2,100,1 Go 
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t t where exists(select 1 from @t where t.dgoodsid=mgoodsid)
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/dqty,
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)
                from @t a
                where lvl=@i
                    and exists(select 1 from @t where a.dgoodsid=mgoodsid)
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
     
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 100.00                                  B001                 1.00                                    100.00                                  3.00                                    300.00                                  0
    A001                 100.00                                  C001                 2.00                                    100.00                                  1.00                                    100.00                                  0
    A001                 100.00                                  D001                 3.00                                    100.00                                  1.00                                    100.00                                  0
    B001                 100.00                                  E001                 1.00                                    100.00                                  1.00                                    100.00                                  1
    B001                 100.00                                  F001                 2.00                                    100.00                                  2.00                                    200.00                                  1
    F001                 100.00                                  G001                 1.00                                    100.00                                  1.00                                    100.00                                  2
    F001                 100.00                                  J001                 2.00                                    100.00                                  1.00                                    100.00                                  2(7 行受影响)
    */--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,DGOODSID ,DQTY,DPRICE,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  E001                 100.00                                  1.00                                    100.00
    B001                 100.00                                  F001                 100.00                                  2.00                                    200.00(2 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  B001                 100.00                                  3.00                                    300.00
    A001                 100.00                                  C001                 100.00                                  1.00                                    100.00
    A001                 100.00                                  D001                 100.00                                  1.00                                    100.00(3 行受影响)
    */
      

  44.   

    htl258兄,为什么要加下面的语句?
    update @t set DAMT=DQTY*DPRICE where DAMT is null
      

  45.   

    再测试:
    exec [Sp_BOM] 'NC163'
    MGOODSID  MQTY  DGOODSID  DQTY  DPRICE   DAMT
    NC163 100.00 DR001  40.00 9.24 369.60
    NC163 100.00 DR009  10.00 6.20 62.00
    NC163 100.00 DR024  12.00 12.30 147.60
    NC163 100.00 NCH1/166 38.00 16.48 626.24-------以上DAMT合计=1205.44  应该单价是  1205.44/100=12.05exec [Sp_BOM] 'NC451'
    MGOODSID  MQTY  DGOODSID  DQTY  DPRICE   DAMT
    NC451 100.00 NC163 15.00 80.36 1205.39    ----这个80.36有点不对吧!
    NC451 100.00 DR009 20.00 6.20 124.00
    NC451 100.00 DR024 30.00 12.30 369.00
    NC451 100.00 DR023 5.00 12.30 61.50
    NC451 100.00 AR451 30.00 28.84 865.20
      

  46.   


    select 1205.39/15.00
    /*---------------------------------------
    80.3593333(1 行受影响)
    */
      

  47.   


    ----B001100.00    F001100.00200.0020000.00  单价没有哪么高,
    下阶的成本单价=DAMT/MQTY  ,传到上阶的应该是单位成本单价才行。
    谢谢!
    另外在我的数据库里面运行:是没有任务数据出现的
    select * from dbo.FUNC_AAAAA('NC163'); select * from dbo.FUNC_AAAAA('NC451'); 
    但运行以下
    select * from dbo.FUNC_AAAAA('A001'); 
    select * from dbo.FUNC_AAAAA('F001'); 
    select * from dbo.FUNC_AAAAA('B001'); 
    都有数据出来的。
      

  48.   


    谢谢关注:
    下阶清单:  这里做100KG NC163 才耗用1205.44元,所以单位成本价/KG应该是  1205.44/100KG=12.05元
    MGOODSID  MQTY  DGOODSID  DQTY  DPRICE  DAMT 
    NC163 100.00 DR001 40.00 9.24 369.60 
    NC163 100.00 DR009 10.00 6.20 62.00 
    NC163 100.00 DR024 12.00 12.30 147.60 
    NC163 100.00 NCH1/166 38.00 16.48 626.24 
      

  49.   

    那个单价对应的物料是DGOODSID而不是MGOODSID,这点要先清楚。
      

  50.   

    再测试: 
    exec [Sp_BOM] 'NC163' 
    MGOODSID  MQTY  DGOODSID  DQTY  DPRICE  DAMT 
    NC163 100.00 DR001 40.00 9.24 369.60 
    NC163 100.00 DR009 10.00 6.20 62.00 
    NC163 100.00 DR024 12.00 12.30 147.60 
    NC163 100.00 NCH1/166 38.00 16.48 626.24 -------以上DAMT合计=1205.44  应该单价是  1205.44/100=12.05   算出来的单位成本价exec [Sp_BOM] 'NC451'    -----NC451引用NC163 ,哪么引用NC163的单位成本单价到NC451 DPRICE
    MGOODSID  MQTY  DGOODSID  DQTY  DPRICE  DAMT 
    NC451 100.00 NC163 15.00 80.36 1205.39    ----这个80.36有点不对吧!  这里DPRICE=12.05
    NC451 100.00 DR009 20.00 6.20 124.00 
    NC451 100.00 DR024 30.00 12.30 369.00 
    NC451 100.00 DR023 5.00 12.30 61.50 
    NC451 100.00 AR451 30.00 28.84 865.20 看看NC163是作为半成品,NC451作为成品,所以NC451取NC163的单位成本价
      

  51.   


    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2)) 
    Insert BOM 
    Select 584,'A001',100.00,'B001',1.00,100.00,1 union all 
    Select 584,'A001',100.00,'C001',2,100,1.00 union all 
    Select 584,'A001',100.00,'D001',3,100,1 union all 
    Select 588,'B001',100.00,'E001',1,100,1 union all 
    Select 588,'B001',100.00,'F001',2,100,1 union all 
    Select 560,'F001',100.00,'G001',1,100,1 union all 
    Select 560,'F001',100.00,'J001',2,100,1 Go 
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t t where exists(select 1 from @t where t.dgoodsid=mgoodsid)
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/mqty, --这里改下测试
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)
                from @t a
                where lvl=@i
                    and exists(select 1 from @t where a.dgoodsid=mgoodsid)
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
     
    /*
    MGOODSID             MQTY                                    DGOODSID             ITEMNO                                  DQTY                                    DPRICE                                  DAMT                                    lvl
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- -----------
    A001                 100.00                                  B001                 1.00                                    100.00                                  3.00                                    300.00                                  0
    A001                 100.00                                  C001                 2.00                                    100.00                                  1.00                                    100.00                                  0
    A001                 100.00                                  D001                 3.00                                    100.00                                  1.00                                    100.00                                  0
    B001                 100.00                                  E001                 1.00                                    100.00                                  1.00                                    100.00                                  1
    B001                 100.00                                  F001                 2.00                                    100.00                                  2.00                                    200.00                                  1
    F001                 100.00                                  G001                 1.00                                    100.00                                  1.00                                    100.00                                  2
    F001                 100.00                                  J001                 2.00                                    100.00                                  1.00                                    100.00                                  2(7 行受影响)
    */--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,DGOODSID ,DQTY,DPRICE,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    B001                 100.00                                  E001                 100.00                                  1.00                                    100.00
    B001                 100.00                                  F001                 100.00                                  2.00                                    200.00(2 行受影响)
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID             MQTY                                    DGOODSID             DQTY                                    DPRICE                                  DAMT
    -------------------- --------------------------------------- -------------------- --------------------------------------- --------------------------------------- ---------------------------------------
    A001                 100.00                                  B001                 100.00                                  3.00                                    300.00
    A001                 100.00                                  C001                 100.00                                  1.00                                    100.00
    A001                 100.00                                  D001                 100.00                                  1.00                                    100.00(3 行受影响)
    */
      

  52.   

    htl258兄,经测试可行,运行速度在5秒之内。
    还有个不情之请,因为我们是做化工的,所以在BOM投料时在子件里面同一原料可以同时出现的例如:
    做A半成品  100%  
    1/ 投入 B  30% 、D 50% 快速分散30分钟
    2/再投入 B 20%研磨QC
    哪么做成的BOM是这样的(BOM体现投料顺序及比例,所以不能合并B为70%)
           A 100
      B30    D50   B20在成本计算当中以上程序就会有点问题了:
    exec [Sp_BOM] 'AV267'   ---成本单价 5278.9/100=52.78      ----这是半成品
    AV267 100.00 DR001 20.00 9.24 184.80
    AV267 100.00 DR002 39.50 7.35 290.33
    AV267 100.00 AR439 .50 47.38 23.69
    AV267 100.00 DR105 40.00 13.39 535.60
    AV267 100.00 DR001 20.00 9.24 184.80
    AV267 100.00 DR002 39.50 7.35 290.33
    AV267 100.00 AR439 .50 47.38 23.69
    AV267 100.00 DR193 40.00 13.39 535.60
    AV267 100.00 DR001 20.00 9.24 184.80
    AV267 100.00 DR002 39.50 7.35 290.33
    AV267 100.00 AR439 .50 47.38 23.69
    AV267 100.00 DR138 40.00 13.18 527.20
    AV267 100.00 DR001 20.00 9.24 184.80
    AV267 100.00 DR002 39.50 7.35 290.33
    AV267 100.00 AR439 .50 47.38 23.69
    AV267 100.00 DR170 40.00 16.48 659.20
    AV267 100.00 DR001 20.00 9.24 184.80
    AV267 100.00 DR002 39.50 7.35 290.33
    AV267 100.00 AR439 .50 47.38 23.69
    AV267 100.00 DR138 40.00 13.18 527.20exec [Sp_BOM] 'AV612'  ----这里出现两次的AV167 为什么这里单价不是52.78   
                            ----这是半成品
    AV612 100.00 AV267 40.00 105.58 10558.44   ----105.58??
    AV612 100.00 AR471 20.00 46.35 927.00
    AV612 100.00 AV267 40.00 105.58 10558.44   ----105.58??
    exec [Sp_BOM] 'GA2967'   ----这才是成品
    GA2967 100.00 AV18 32.00 44.79 4479.26
    GA2967 100.00 AV612 6.00 220.44 22043.88
    GA2967 100.00 AV168 10.00 32.18 3218.08
    GA2967 100.00 PA3005 15.00 79.06 7905.76
    GA2967 100.00 PA3014 30.00 95.49 9549.13
    GA2967 100.00 . .00 .00 .00
    GA2967 100.00 DR019 5.00 10.40 52.00
      

  53.   


    哈哈,好长的回复啊
    我手动添加过数据了,87怎么不对,你看下原始数据
    另外说下,所谓的Mqty,即父栏位数量,都设为1,是比较合理的,子数量再考虑相应倍率
      

  54.   

    [Quote=引用 70 楼 playwarcraft 的回复:]
    引用 54 楼 sankyqiu 的回复:
    playwarcraft兄在吗?这里能不能再帮忙处理一下,这个方法也不错呀!
    p_id      pqty        tmp_id    cqty        dprice      DAM
    ---------- ----------- ---------- ----------- ----------- -----------
    A001      1          B001      1          87          87  -----这里不正确呀!
    A001      1          C001      2          5          10
    A001      1          D001      1          5          5*/GOdroptable bomdropproc
    哈哈,好长的回复啊
    我手动添加过数据了,87怎么不对,你看下原始数据
    另外说下,所谓的Mqty,即父栏位数量,都设为1,是比较合理的,子数量再考虑相应倍率谢谢!
      

  55.   


    以下是在我的数据库里面运行的
    exec dbo.usp_bom 'f001'    最下层正确
    P_ID PQTY TMP_ID  CQTY DPRICE DAM
    F001 100.0 G001 100.0 1.0 100.0
    F001 100.0 J001 100.0 1.0 100.0
    exec dbo.usp_bom 'b001'   ----中间层   F001  DPRICE 为0? DAM 2百万?  
    P_ID PQTY TMP_ID  CQTY DPRICE DAM
    B001 100.0 E001 100.0 1.0 100.0
    B001 100.0 F001 100.0 0.0 2000000.0  ----这里有点小问题
    exec dbo.usp_bom 'A001'
    P_ID PQTY TMP_ID  CQTY DPRICE DAM
    A001 100.0 B001 100.0 0.0 3000000.0  ------  0.0
    A001 100.0 C001 100.0 1.0 100.0
    A001 100.0 D001 100.0 1.0 100.0
      

  56.   

    --> 生成测试数据表:BOMIf not object_id('[BOM]') is null
    Drop table [BOM]
    Go
    Create table [BOM]([BILLID] int,[MGOODSID] nvarchar(4),[MQTY] decimal(18,2),[DGOODSID] nvarchar(4),[ITEMNO] decimal(18,2),[DQTY] decimal(18,2),[DPRICE] decimal(18,2)) 
    Insert BOM 
    Select 584,'A001',100.00,'B001',1.00,100.00,1 union all 
    Select 584,'A001',100.00,'C001',2,100,1.00 union all 
    Select 584,'A001',100.00,'D001',3,100,1 union all 
    Select 584,'A001',100.00,'B001',1.00,40.00,1 union all --增加一列
    Select 588,'B001',100.00,'E001',1,100,1 union all 
    Select 588,'B001',100.00,'F001',2,100,1 union all 
    Select 560,'F001',100.00,'G001',1,100,1 union all 
    Select 560,'F001',100.00,'J001',2,100,1 Go 
    --Select * from BOM-->SQL查询如下:If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t t where exists(select 1 from @t where t.dgoodsid=mgoodsid)
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/(select sum(mqty) from @t where DGOODSID=a.DGOODSID),
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/(select count(1) from @t where DGOODSID=a.DGOODSID)
                from @t a
                where lvl=@i
                    and exists(select 1 from @t where a.dgoodsid=mgoodsid)
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    select * from fn_bom('a001') 
     
    /*
    MGOODSID MQTY DGOODSID ITEMNO DQTY DPRICE DAMT lvl
    A001 100.00 B001 1.00 100.00 3.00 300.00 0
    A001 100.00 C001 2.00 100.00 1.00 100.00 0
    A001 100.00 D001 3.00 100.00 1.00 100.00 0
    A001 100.00 B001 1.00 40.00 3.00 300.00 0
    B001 100.00 E001 1.00 100.00 1.00 100.00 1
    B001 100.00 E001 1.00 100.00 1.00 100.00 1
    B001 100.00 F001 2.00 100.00 2.00 200.00 1
    B001 100.00 F001 2.00 100.00 2.00 200.00 1
    F001 100.00 G001 1.00 100.00 1.00 100.00 2
    F001 100.00 G001 1.00 100.00 1.00 100.00 2
    F001 100.00 J001 2.00 100.00 1.00 100.00 2
    F001 100.00 J001 2.00 100.00 1.00 100.00 2
    */--计算成本存储过程
    If not object_id('[Sp_BOM]') is null
        Drop proc [Sp_BOM]
    Go
    Create proc Sp_BOM(@GOODSID varchar(20))
    as
    select MGOODSID,MQTY,DGOODSID ,DQTY,DPRICE,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    GO--调用过程
    exec [Sp_BOM] 'B001'
    /*
    MGOODSID MQTY DGOODSID DQTY DPRICE DAMT
    B001 100.00 E001 100.00 1.00 100.00
    B001 100.00 F001 100.00 2.00 200.00
    */
    exec [Sp_BOM] 'A001'
    /*
    MGOODSID MQTY DGOODSID DQTY DPRICE DAMT
    A001 100.00 B001 100.00 3.00 300.00
    A001 100.00 C001 100.00 1.00 100.00
    A001 100.00 D001 100.00 1.00 100.00
    A001 100.00 B001 40.00 3.00 300.00
    */
      

  57.   

    我的算法是以 pqty 参考1 来计算的,
    你看算的过程中有用到 cqty
    现在你的cqty是100, 当然会多出很多倍
      

  58.   

    If not object_id('[Fn_BOM]') is null
        Drop function [Fn_BOM]
    Go
    Create Function Fn_BOM(@MGoodsID varchar(20))
    returns @t table(MGOODSID varchar(20),MQTY dec(18,2),DGOODSID varchar(20),ITEMNO dec(18,2),DQTY dec(18,2),DPRICE dec(18,2),DAMT dec(18,2),lvl int)
    as 
    begin
        declare @lvl int
        set @lvl=0
        insert @t select MGOODSID,MQTY,DGOODSID,ITEMNO,DQTY,DPRICE,NULL,@lvl from BOM where MGoodsID=@MGoodsID 
        while @@rowcount>0
            begin
                set @lvl=@lvl+1
                insert @t 
                select a.MGOODSID,a.MQTY,a.DGOODSID,a.ITEMNO,a.DQTY,a.DPRICE,a.DQTY*a.DPRICE,@lvl 
                from BOM a,@t b
                where a.MGoodsID=b.DGoodsID 
                    and b.lvl=@lvl-1
            end
        declare @i int
        select @i=max(lvl) from @t t where exists(select 1 from @t where t.dgoodsid=mgoodsid)
        while @i>=0
            begin
                update a set 
                    dprice=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/(select sum(mqty) from @t where DGOODSID=a.DGOODSID),
                    damt=(select sum(damt) from @t where a.DGOODSID=MGOODSID)/(select count(1) from @t where DGOODSID=a.DGOODSID)            from @t a
                where lvl=@i
                    and exists(select 1 from @t where a.dgoodsid=mgoodsid)
                set @i=@i-1
            end
        update @t set DAMT=DQTY*DPRICE where DAMT is null
        return
    end
    go
    改动红字部份
      

  59.   

    请进这里,还有100分在如下地址:
    因为以下地址给160分,但系统不给我出160分所以只出100
    http://topic.csdn.net/u/20090830/20/3f4f3d9e-9ed4-4bdc-a06b-469a39478ce4.html
      

  60.   

    --计算成本函数
    If not object_id('[FN_BOMCOST]') is null
        Drop FUNCTION [FN_BOMCOST]
    Go
    Create FUNCTION [FN_BOMCOST](@GOODSID varchar(20))
    returns table
    as
    return(
    select MGOODSID,MQTY,DGOODSID ,DQTY,DPRICE,DAMT 
    from fn_bom(@GOODSID) 
    where MGOODSID=@GOODSID
    )
    GOselect * from [FN_BOMCOST]('B001')
    /*
    MGOODSID MQTY DGOODSID DQTY DPRICE DAMT
    B001 100.00 E001 100.00 1.00 100.00
    B001 100.00 F001 100.00 2.00 200.00
    */