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
我想做的只是从 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