Sql server 递归自链接表的SQL语句
我有一个BOM公式表,其中列出了BOM项及其“组件”。表有两个字段:BOM表字段和零部件字段。组件项可能是另一个公式。例如:Sql server 递归自链接表的SQL语句,sql-server,Sql Server,我有一个BOM公式表,其中列出了BOM项及其“组件”。表有两个字段:BOM表字段和零部件字段。组件项可能是另一个公式。例如: BOM, Component A1, C1 A1, C2 A1, C3 A2, C4 A2, C5 C2, C6 C2, C7 C7, C8 C7, C9 C7, C10 A1项具有C1、C2和C3部件 C1和C3是原材料 C2是BOM类型,它有C6和C7组件 如何使用SQL列出递归类型查询以查找所有原材料?递归级别未知。在这种情况下,A1具有C1、C3、C6
BOM, Component
A1, C1
A1, C2
A1, C3
A2, C4
A2, C5
C2, C6
C2, C7
C7, C8
C7, C9
C7, C10
A1项具有C1、C2和C3部件
- C1和C3是原材料
- C2是BOM类型,它有C6和C7组件
C2是由C6和C7组装而成的BOM项。
C7是由C8、C9和C10组装而成的BOM项 BOM表项目A1的组件为C1、C3、C6、C8、C9和C10。C2和C7是BOM项,不是原材料项 输出将是:
A1 C1
A1 C3
A1 C6
A1 C8
A1 C9
A1 C10
A2 C4
A2 C5
下面的记录是可选的。它可以在输出上,也可以不在输出上
C2 C6
C2 C8
C2 C9
C2 C10
C7 C8
C7 C9
C7 C10
编辑:现在只显示不属于另一个组件的
BOM
WITH DirectReports (BOM, Component, Level)
AS
(
-- Anchor member definition
SELECT e.BOM, e.Component, 0 AS Level
FROM dbo.BOM AS e
UNION ALL
-- Recursive member definition
SELECT d.BOM, e.Component, Level + 1
FROM dbo.BOM AS e
INNER JOIN DirectReports AS d
ON e.BOM = d.Component
AND d.Level = Level
)
-- Statement that executes the CTE
SELECT DR.BOM, DR.Component, DR.Level, B.Component
FROM DirectReports DR
LEFT JOIN BOM B
ON DR.BOM = B.Component
WHERE B.Component IS NULL
ORDER BY BOM
GO
输出
| BOM | Component | Level | Component |
|-----|-----------|-------|-----------|
| A1 | C1 | 0 | (null) |
| A1 | C2 | 0 | (null) |
| A1 | C3 | 0 | (null) |
| A1 | C6 | 1 | (null) |
| A1 | C7 | 1 | (null) |
| A1 | C8 | 2 | (null) |
| A1 | C9 | 2 | (null) |
| A1 | C10 | 2 | (null) |
| A2 | C4 | 0 | (null) |
| A2 | C5 | 0 | (null) |
这不会降低到任何级别,但想法很简单,您可以添加任意多个级别
DECLARE @tbl TABLE(BOM VARCHAR(10), Component VARCHAR(10));
INSERT INTO @tbl VALUES
('A1','C1')
,('A1','C2')
,('A1','C3')
,('A2','C4')
,('A2','C5')
,('C2','C6')
,('C2','C7')
,('C7','C8')
,('C7','C9')
,('C7','C10');
WITH rCTE AS
(
SELECT tbl.BOM,tbl.Component,1 AS Level
FROM @tbl AS tbl
WHERE NOT EXISTS(SELECT 1 FROM @tbl WHERE Component=tbl.BOM)
UNION ALL
SELECT nxt.BOM,nxt.Component,rCTE.Level+1
FROM rCTE
INNER JOIN @tbl AS nxt ON rCTE.Component=nxt.BOM
)
SELECT lvl1.BOM AS l1
,ISNULL(lvl1.Component,lvl2.BOM) AS l2
,ISNULL(lvl2.Component,lvl3.BOM) AS l3
,ISNULL(lvl3.Component,lvl4.BOM) AS l4
FROM rCTE AS lvl1
LEFt JOIN rCTE AS lvl2 ON lvl1.Component=lvl2.BOM AND lvl2.Level=2
LEFt JOIN rCTE AS lvl3 ON lvl2.Component=lvl3.BOM AND lvl3.Level=3
LEFt JOIN rCTE AS lvl4 ON lvl3.Component=lvl4.BOM AND lvl4.Level=4
WHERE lvl1.Level=1
结果
+----+----+------+------+
| A1 | C1 | NULL | NULL |
+----+----+------+------+
| A1 | C2 | C6 | NULL |
+----+----+------+------+
| A1 | C2 | C7 | C8 |
+----+----+------+------+
| A1 | C2 | C7 | C9 |
+----+----+------+------+
| A1 | C2 | C7 | C10 |
+----+----+------+------+
| A1 | C3 | NULL | NULL |
+----+----+------+------+
| A2 | C4 | NULL | NULL |
+----+----+------+------+
| A2 | C5 | NULL | NULL |
+----+----+------+------+
更新
如果将最终更改为此
SELECT lvl1.BOM AS l1
,COALESCE
(
--add more levels top down
ISNULL(lvl3.Component,lvl4.BOM)
,ISNULL(lvl2.Component,lvl3.BOM)
,ISNULL(lvl1.Component,lvl2.BOM)
) AS Comp
FROM rCTE AS lvl1
LEFt JOIN rCTE AS lvl2 ON lvl1.Component=lvl2.BOM AND lvl2.Level=2
LEFt JOIN rCTE AS lvl3 ON lvl2.Component=lvl3.BOM AND lvl3.Level=3
LEFt JOIN rCTE AS lvl4 ON lvl3.Component=lvl4.BOM AND lvl4.Level=4
--add more levels
WHERE lvl1.Level=1
你会得到这个,它似乎非常接近你需要的东西
A1 C1
A1 C6
A1 C8
A1 C9
A1 C10
A1 C3
A2 C4
A2 C5
C2是BOM类型的项目,它将链接到C6和C7,C7是BOM类型的项目,它将链接到C8、C9和C10。对于BOM表A1记录,A1-C3和A1-C7记录是否可以从结果中抑制?我需要组件字段的结果仅为原材料项。我使用下面的代码,可以消除A1-C3和A1-C7。-执行CTE从DirectReports中选择X.BOM、X.Component、X.Level作为X LEFT JOIN DirectReports作为Y on X.Component=Y.BOM的语句,其中Y.BOM按X为空顺序。BOM@YellowLarry对不起,你说的我什么都听不懂。你能给我举个例子吗?编辑问题并让我知道。但是我现在要睡觉了,所以只有明天才能检查。我只是不明白为什么你不想显示C1,C2和A1,A2,如果两者都是BOM
(顺便问一下BOM是什么意思)。。。。或者您想要的BOM
不是任何其他组件的一部分?编辑完我的问题后,现在我理解您的第二条评论。这不是解决你的问题吗?嗨,拉里,我刚刚更新了我的答案。我不认为存在递归的特殊方法。你可以使用光标或CLR路径…@Shnugo我认为我的递归解决方案应该可以做到这一点。@JuanCarlosOropeza太棒了!加油!更新的选择结果是我需要的。谢谢