Sql server 递归自链接表的SQL语句

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公式表,其中列出了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、C8、C9和C10原料

通过以下示例更新问题:

BOM表是从组件项组装而成的项。需要查询以获取BOM项的所有原材料组件以执行生产材料计划

A1是由C1、C2和C3组装而成的BOM项。
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太棒了!加油!更新的选择结果是我需要的。谢谢