web-dev-qa-db-ja.com

真ん中に再帰的なテーブルを持つ3つのテーブルの結合を構築しますか?

3つの関連テーブルがあります。Parts、PartGroup、MarkupGroupです。

パーツはシンプルです。

PartID          artificial primary key
Part            part number
PartGroupID     Foreign key

サンプルデータ:

1   T1000           5
2   wizbang gold    17
3   flux capacitor  2

PartGroupは、自己リンクされた親キーでモデル化された非循環有向グラフ(ツリー)です

PartGroupID     artificial primary key
Description     name of group
ParentID        foreign key linked to PartGroupID
MarkupGroupID   foreign key linked to MarkupGroup

サンプルデータは次のようになります。

1   system      null    null
2   component   null    1 
3   software    null    2
4   abc         1       3
5   xyz         1       4
6   123         4       null
7   456         4       null
8   789         5       null
9   a1          6       null
10  b2          6       null
11  c3          7       null
12  d4          7       null
13  e5          8       null  
14  f6          8       null
15  alpha       3       null
16  beta        3       null
17  gamma       3       null

MarkupGroupは、マークアップ係数をセットとして複数のPartGroupに適用します。

MarkupGroupID   primary key
MarkupFactor    numeric attribute field

サンプルデータ-

1   15
2   20
3   25
4   22

パーツテーブルの各パーツに適切なマークアップ金額を返すクエリを作成する必要があります。複数のマークアップを1つのパーツに適用できる場合はありません。マークアップを見つけるにはグラフを再帰的に調べる必要がありますが、クエリの時点では、null以外のマークアップを見つけるために再帰が必要なレベルの数がわかりません。

ツリーの途中で、パーツがマージンへの可能な複数の結合に遭遇することは決してないので、実行する必要のある累積はありません。

T1000のタイプはxyzで、MarginGroupへの外部キーがあるため、結合して値を取得できます。親も持っていますが、必要な値があるのでそれは関係ありません。

Wizbang Goldはガンマグループソフトウェアであり、外部キーはありませんが、親ノードの「ソフトウェア」が実行するので、それを返す必要があります。

フラックスコンデンサはコンポーネントであり、MarginGroupへの直接外部キーを持っています。その値を返します。

したがって、結果は次のようになります。

1   T1000           22
2   wizbang gold    20
3   flux capacitor  15

これを実現するには、再帰的なCTEとAPPLYのフレーバーが必要になると確信していますが、現時点では私の脳はうまく機能していません。ミドルテーブルの再帰的な性質がなければ、これは非常に簡単です。プラットフォームはMS-SQLです。

5
Jeff Sacksteder

あなたはCTEでMarkupGroupIDを持ってトップダウンで再帰を行うことができます。

with C as
(
  select P.PartGroupID,
         P.ParentID,
         P.MarkupGroupID
  from PartGroup as P
  where P.ParentID is null
  union all 
  select P.PartGroupID,
         P.ParentID,
         coalesce(P.MarkupGroupID, C.MarkupGroupID)
  from PartGroup as P 
    inner join C 
      on P.ParentID = C.PartGroupID
)
select P.PartID,
       P.Part,
       MG.MarkupFactor
from Parts as P
  inner join C
    on P.PartGroupID = C.PartGroupID
  inner join MarkupGroup as MG
    on C.MarkupGroupID = MG.MarkupGroupID
order by P.PartID

SQLフィドル

再帰CTEは、次のような派生テーブルを作成します。

PartGroupID ParentID    MarkupGroupID
----------- ----------- -------------
1           NULL        NULL
2           NULL        1
3           NULL        2
15          3           2
16          3           2
17          3           2
4           1           3
5           1           4
8           5           4
13          8           4
14          8           4
6           4           3
7           4           3
11          7           3
12          7           3
9           6           3
10          6           3

マークアップに接続されていないパーツグループのパーツが必要な場合は、メインクエリでMarkupGroupに対して外部結合を使用できます。

with C as
(
  select ...
)
select P.PartID,
       P.Part,
       MG.MarkupFactor
from Parts as P
  inner join C
    on P.PartGroupID = C.PartGroupID
  left outer join MarkupGroup as MG
    on C.MarkupGroupID = MG.MarkupGroupID
order by P.PartID
5
Mikael Eriksson