web-dev-qa-db-ja.com

ツリーNode計算-SQL Server

私が成し遂げようとしていることの助けをお願いします。

私の会社が製造する部品は、サブアセンブリとサブアセンブリのサブアセンブリから構築されています。これは次のようになります。

             1
         /   \  \
        /     |   \
       2      3    7
      / \    / \
     4   5  4   6

4と5が一緒になって2、4、6が3を作る場合、アセンブリ2、3、7が1を作る。

私のテーブルはこのように見えます。

+------+-----+-------+----------+----------------+
| ROOT | SUB | LEVEL | LEADTIME | TOP LEVEL PART |
+------+-----+-------+----------+----------------+
|    1 |   1 |     0 |        4 |              1 |
|    1 |   2 |     1 |        2 |              1 |
|    1 |   3 |     1 |        5 |              1 |
|    1 |   7 |     1 |       20 |              1 |
|    2 |   4 |     1 |        4 |              1 |
|    2 |   5 |     1 |        1 |              1 |
|    3 |   4 |     2 |        4 |              1 |
|    3 |   6 |     2 |        5 |              1 |
+------+-----+-------+----------+----------------+

各部品には、それを作るのにかかる時間のリードタイムがあります。私がやりたいことは、最上位の部品番号を渡して、部品の全体的なリードタイムを計算することです。

当初は、レベルごとにグループ化して、レベルごとの最大リードタイムを取り、それらを一緒に追加できると思っていましたが、正確ではありません。レベル1パート7の作成には20日かかるため、7が作成されている間、他のすべてのパートを作成することができます。計算は、その親を消費する部分に基づく必要があります(より良いフレーズが必要なため)。

私がする必要があるのは、ツリーを通るすべてのルートのリードタイムを計算し、それが進むにつれてリードタイムを合計することです。だから私は次のようなテーブルを返したいと思います。

+----+----------------+-------------------------+------+------------+
| ID | Top Level Part | Parts Nodes Combination | Days | [BASED ON] |
+----+----------------+-------------------------+------+------------+
| 1  | 1              | 1 >> 2 >> 4             | 10   | 4 + 2 + 4  |
| 2  | 1              | 1 >> 2 >> 5             | 7    | 4 + 2 + 1  |
| 3  | 1              | 1 >> 3 >> 4             | 13   | 4 + 5 + 4  |
| 4  | 1              | 1 >> 3 >> 6             | 14   | 4 + 5 + 5  |
| 5  | 1              | 1 >> 7                  | 24   | 4 + 20     |
+----+----------------+-------------------------+------+------------+

次に、「日数の最大値」列を見つけると、パート1の全体のリードタイムが24日であることがわかります。

私の投稿が理解しやすくなり、すべてが正しくフォーマットされていることを願っています。私は再帰的なSQLクエリを読み込もうとしましたが、それらを理解するのに苦労しています。私がこれまでに持っている可能性が最も高いレベルの数は4であるため、PCに集中しすぎないようにしたいと思います。その場合、一度に1つのパーツを実行するのではなく、すべてのパーツをパススルーできるようにしたいのです(したがって、テーブルに最上位のパーツ列があるのはなぜですか)。

任意の助けやアドバイスをいただければ幸いです。

6
David

このソリューションは中間ノードも取得します

;WITH RecursiveCTE
AS
(
SELECT  [SUB] , 
        [SUB] as [Top Level Part],
        CAST([SUB] as varchar(255)) as [Parts Nodes Combination],
        0 AS [LEVEL],
        [LEADTIME]  as [Days],
        CAST([LEADTIME] as varchar(255)) as [BASED ON]
FROM dbo.Levels s1
WHERE [LEVEL] = 0

UNION ALL

SELECT  s1.SUB as [Top Level Part],
        RecursiveCTE.[Top Level Part],
        CAST(RecursiveCTE.[Parts Nodes Combination]+ ' >> ' + cast(s1.[SUB] as varchar(255)) as varchar(255)),
        RecursiveCTE.[LEVEL] + 1 as [LEVEL],
        RecursiveCTE.[Days] + s1.[LEADTIME] as [Days],
        CAST(RecursiveCTE.[BASED ON] + ' + ' + CAST(s1.[LEADTIME] as varchar(255))  as  varchar(255))
FROM dbo.Levels s1
INNER JOIN RecursiveCTE 
ON s1.[ROOT] = RecursiveCTE.[SUB]
WHERE s1.[LEVEL] > 0
)
SELECT * FROM RecursiveCTE
WHERE [LEVEL] != 0;

結果

SUB Top Level Part  Parts Nodes Combination LEVEL   Days    BASED ON
2       1               1 >> 2                  1       6       4 + 2
3       1               1 >> 3                  1       9       4 + 5
7       1               1 >> 7                  1       24      4 + 20
4       1               1 >> 3 >> 4             2       13      4 + 5 + 4
6       1               1 >> 3 >> 6             2       14      4 + 5 + 5
4       1               1 >> 2 >> 4             2       10      4 + 2 + 4
5       1               1 >> 2 >> 5             2       7       4 + 2 + 1

DB <>フィドル

中間ノードを除外したい場合:

;WITH RecursiveCTE
AS
(
SELECT  [SUB] , 
        [SUB] as [Top Level Part],
        CAST([SUB] as varchar(255)) as [Parts Nodes Combination],
        0 AS [LEVEL],
        [LEADTIME]  as [Days],
        CAST([LEADTIME] as varchar(255)) as [BASED ON]
FROM dbo.Levels s1
WHERE [LEVEL] = 0

UNION ALL

SELECT  s1.SUB as [Top Level Part],
        RecursiveCTE.[Top Level Part],
        CAST(RecursiveCTE.[Parts Nodes Combination]+ ' >> ' + cast(s1.[SUB] as varchar(255)) as varchar(255)),
        RecursiveCTE.[LEVEL] + 1 as [LEVEL],
        RecursiveCTE.[Days] + s1.[LEADTIME] as [Days],
        CAST(RecursiveCTE.[BASED ON] + ' + ' + CAST(s1.[LEADTIME] as varchar(255))  as  varchar(255))
FROM dbo.Levels s1
INNER JOIN RecursiveCTE 
ON s1.[ROOT] = RecursiveCTE.[SUB]

WHERE s1.[LEVEL] > 0

)

SELECT * FROM RecursiveCTE
WHERE [LEVEL] != 0
AND NOT EXISTS 
(
SELECT * FROM
dbo.Levels s2
WHERE RecursiveCTE.SUB = s2.[ROOT])
;

結果

SUB Top Level Part  Parts Nodes Combination LEVEL   Days    BASED ON
7           1               1 >> 7           1      24      4 + 20
4           1               1 >> 3 >> 4      2      13      4 + 5 + 4
6           1               1 >> 3 >> 6      2      14      4 + 5 + 5
4           1               1 >> 2 >> 4      2      10      4 + 2 + 4
5           1               1 >> 2 >> 5      2      7       4 + 2 + 1

DB <>フィドル

使用するテーブルとデータ

CREATE TABLE dbo.Levels ([PARTID] INT,[ROOT] int,[SUB] int,[LEVEL] int, [LEADTIME] int,[TOP LEVEL PART] int);
--PartID added
INSERT INTO dbo.Levels
 ([PARTID], [ROOT] ,[SUB] ,[LEVEL] , [LEADTIME] ,[TOP LEVEL PART])

VALUES
(1,1 , 1 ,0 ,4 ,1 ),
(1,1 , 2 ,1 ,2 ,1 ),
(1,1 , 3 ,1 ,5 ,1 ),
(1,1 , 7 ,1 ,20 ,1 ),
(1,2 , 4 ,1 ,4 ,1 ),
(1,2 , 5 ,1 ,1 ,1 ),
(1,3 , 4 ,2 ,4 ,1 ),
(1,3 , 6 ,2 ,5 ,1 );

編集

オペレーションコメント:

データが何度も繰り返されていることに気づきました(特に大きなアセンブリで)

基本的に私はサブルーター1691を最上位ルーター1731に持っています。パーツノードの組み合わせは1731-1727-1691で、これはまったく同じ列を8回繰り返します。次に、別のノード(1731-1727-1691-1682)を導入すると、これは168回繰り返されます。これがすべてのケースに当てはまります。 3レベルのノードは8回繰り返され、4レベルのノードは168回繰り返されているようです。

別のものでそれははるかに少ない回数繰り返されます。ツリー内のユニークなパーツの数と関係があるのか​​と思います。

私はそれを理解したと思います! 1つのサブが複数の異なるトップレベルパーツに表示される場合があります。 recursiveCTEテーブルへの結合で、「およびRecursiveCTE。[トップレベルパーツ] = s1.TopLevelRouter」も追加しました。これでトリックは完了です。

変更が必要なクエリの一部:

 ...    
FROM dbo.Levels s1
INNER JOIN RecursiveCTE 
ON s1.[ROOT] = RecursiveCTE.[SUB]
and RecursiveCTE.[Top Level Part] = s1.TopLevelRouter
WHERE s1.[LEVEL] > 0
)
SELECT * FROM RecursiveCTE
WHERE [LEVEL] != 0;
3
Randi Vertongen