用于递归自链接表的SQL

时间:2016-05-12 22:03:12

标签: 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项目的所有原材料?递归级别未知。在这种情况下,A1具有C1,C3,C6,C8,C9和C10原料。

通过以下示例更新问题:

BOM是从组件项目组装的项目。需要查询才能获得物料清单物料的所有原料成分以进行生产物料计划。

A1是BOM项目,由C1,C2和C3组装而成 C2是BOM项目,由C6和C7组装而成 C7是BOM项目,由C8,C9和C10组装而成。

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

2 个答案:

答案 0 :(得分:2)

已编辑:现在只会显示不属于其他组件的BOM

SQL Fiddle DEMO

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) |

答案 1 :(得分:1)

这不会达到任何级别,但这个想法很简单,您可以添加任意数量的级别

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更改为此

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