SQL 递归 CTE 'where-used' / BOM 爆炸

SQL Recursive CTE 'where-used' / BOM explosion

我想做的只是从 BOM table(物料清单)中获取与 BOMVERSION 相关的项目 components/products,然后从 components/products 中获取相关的项目将他们的相关组件和产品等降低到 7 个级别。然后我想调整结果,以便将相关项目放入列 0, 1, 2, 3, 4, 5, 6, 7

请参阅随附的示例数据和代码。我使用的是 dynamics AX 2012 R2,但这个示例可以应用于任何使用 materials/products 的系统。但是,我无法完成查询(我知道我没有 dataareaid 和为简单起见而遗漏的分区)。该关系是来自 BOM 的项目 ID table 通过 BOMID 与 BOMVERSION 中的项目 ID 相关。

更新:我已将数据等简化为 simple/clear材料。因此,我想从一个基本组件开始,然后按级别分解关系。

DDL + DML:

    USE tempdb;

IF OBJECT_ID('tempdb..#BOM') IS NOT NULL
    DROP TABLE #BOM;

CREATE TABLE #BOM
    (
      ITEMID NVARCHAR(10) ,
      BOMID NVARCHAR(10) ,
      MATERIALNAME NVARCHAR(10)
    );

INSERT  INTO #BOM
VALUES  ( N'113621', -- ITEMID - nvarchar(10)
          N'1',  -- BOMID - nvarchar(10)
          N'Wood'  -- MATERIALNAME - nvarchar(10)
          );

INSERT  INTO #BOM
VALUES  ( N'234517', -- ITEMID - nvarchar(10)
          N'2',  -- BOMID - nvarchar(10)
          N'Metal'  -- MATERIALNAME - nvarchar(10)
          );

INSERT  INTO #BOM
VALUES  ( N'378654', -- ITEMID - nvarchar(10)
          N'3',  -- BOMID - nvarchar(10)
          N'Glass'  -- MATERIALNAME - nvarchar(10)
          );

IF OBJECT_ID('tempdb..#BOMVERSION') IS NOT NULL
    DROP TABLE #BOMVERSION;

CREATE TABLE #BOMVERSION
    (
      ITEMID NVARCHAR(10) ,
      BOMID NVARCHAR(10) ,
      NAME NVARCHAR(20)
    );

INSERT  INTO #BOMVERSION
VALUES  ( N'113477', -- ITEMID - nvarchar(10)
          N'1', -- BOMID - nvarchar(10)
          N'Oak'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113608', -- ITEMID - nvarchar(10)
          N'1', -- BOMID - nvarchar(10)
          N'Pine'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113622', -- ITEMID - nvarchar(10)
          N'1', -- BOMID - nvarchar(10)
          N'Wood Table'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113683', -- ITEMID - nvarchar(10)
          N'2', -- BOMID - nvarchar(10)
          N'Aluminium'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113689', -- ITEMID - nvarchar(10)
          N'2', -- BOMID - nvarchar(10)
          N'Steel'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113693', -- ITEMID - nvarchar(10)
          N'2', -- BOMID - nvarchar(10)
          N'Metal table'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113694', -- ITEMID - nvarchar(10)
          N'3', -- BOMID - nvarchar(10)
          N'Glass'  -- NAME - nvarchar(10)
          );

INSERT  INTO #BOMVERSION
VALUES  ( N'113695', -- ITEMID - nvarchar(10)
          N'3', -- BOMID - nvarchar(10)
          N'Glass BookCase'  -- NAME - nvarchar(10)
          );

--Query

WITH    BOM1
          AS ( SELECT   B.ITEMID AS BITEMID ,
                        BV.ITEMID AS BVITEMID ,
                        B.MATERIALNAME ,
                        B.BOMID
               FROM     #BOM AS B
                        JOIN #BOMVERSION AS BV ON BV.BOMID = B.BOMID
             ),
        EXPLODE
          AS ( SELECT   B.BITEMID ,
                        B.MATERIALNAME ,
                        B.BVITEMID ,
                        B.BOMID ,
                        0 AS [Level]
               FROM     BOM1 AS B
               UNION ALL
               SELECT   B.BITEMID ,
                        E.MATERIALNAME ,
                        E.BVITEMID ,
                        E.BOMID ,
                        [E].[Level] + 1
               FROM     EXPLODE AS E
                        JOIN BOM1 AS B ON B.BOMID = E.BOMID
               WHERE    E.Level <= 6   --narrowing levels                   
             )
    SELECT  *
    FROM    EXPLODE PIVOT ( MAX(BVITEMID) FOR Level IN ( [0], [1], [2], [3],
                                                         [4], [5], [6], [7] ) ) AS PVTBOM;

输出看起来像

嗯,这只是为了排除错误并得到结果,但我不知道结果是否正确:

WITH    BOM1
          AS ( SELECT   B.ITEMID AS BITEMID ,
                        BV.ITEMID AS BVITEMID ,
                        B.BOMID
               FROM     #BOM AS B
                        JOIN #BOMVERSION AS BV ON BV.BOMID = B.BOMID
             ),
        EXPLODE
          AS ( SELECT   B.BITEMID ,
                        B.BVITEMID ,
                        B.BOMID ,
                        0 AS [Level]
               FROM     BOM1 AS B
               UNION ALL
               SELECT   B.BITEMID ,
                        E.BVITEMID ,
                        E.BOMID ,
                        [E].[Level] + 1
               FROM     EXPLODE AS E
                        JOIN BOM1 AS B ON B.BOMID = E.BOMID
               WHERE e.Level <= 6   --narrowing levels                   
             )


    SELECT  *
    FROM    EXPLODE PIVOT ( MAX(BVITEMID) FOR Level IN ( [0], [1], [2], [3],
                                                         [4], [5], [6], [7] ) ) AS PVTBOM

您有 maxrecursion = 7 - 这不是缩小级别的地方。 CTE.

中的递归部分内部的级别变窄了

我怀疑你的递归没有组织好,所以你能简化你的测试数据吗?只留下几行并显示预期的输出。

编辑 1:

WITH    p AS ( SELECT   *
               FROM     ( SELECT    itemid ,
                                    bomid ,
                                    ROW_NUMBER() OVER ( PARTITION BY Bomid ORDER BY itemid ) rn
                          FROM      #BOMVERSION
                        ) t PIVOT ( MAX(itemid) FOR rn IN ( [1], [2], [3], [4],
                                                            [5], [6], [7], [8] ) ) p
             )
    SELECT  *
    FROM    #bom b
JOIN p ON b.bomid = p.bomid    

编辑2:

;WITH    cte
          AS ( SELECT   b.itemid AS originalitem ,
                        b.bomid AS originalbom ,
                        b.bomid ,
                        bv.itemid AS parent ,
                        0 AS level
               FROM     #BOM b
                        JOIN #BOMVERSION bv ON bv.bomid = b.bomid
               UNION ALL
               SELECT   c.originalitem ,
                        c.originalbom ,
                        b.bomid ,
                        bv.itemid ,
                        c.level + 1
               FROM     cte c
                        JOIN #BOM b ON c.parent = b.itemid
                        JOIN #BOMVERSION bv ON bv.bomid = b.bomid
               WHERE    c.level <= 6
             ),
        tree
          AS ( SELECT   originalitem ,
                        originalbom ,
                        parent ,
                        level
               FROM     cte
             )
    SELECT  *
    FROM    tree PIVOT ( MAX(parent) FOR level IN ( [0], [1], [2], [3], [4], [5], [6], [7] ) ) AS p