6

階層を持つ資産データベースに取り組んでいます。また、アセットを効果的にポイントする「ReferenceAsset」テーブルもあります。リファレンス アセットは基本的にオーバーライドとして機能しますが、独自の新しいアセットであるかのように選択されます。設定されるオーバーライドの 1 つは、parent_id です。

階層の選択に関連する列:
アセット: id (プライマリ)、parent_id
アセット参照: id (プライマリ)、asset_id (外部キー->アセット)、parent_id (常にアセット)
---EDITED 5/27----

関連するテーブル データの例 (結合後):

   id  | asset_id | name         |  parent_id  | milestone | type

    3       3       suit               null        march      shape
    4       4       suit_banker         3          april      texture
    5       5       tie                null        march      shape
    6       6       tie_red             5          march      texture
    7       7       tie_diamond         5          june       texture
   -5       6       tie_red             4          march      texture

id < 0 (最後の行のように) は、参照されているアセットを示します。参照されたアセットには、オーバーライドされるいくつかの列があります (この場合、parent_id のみが重要です)。

4 月からすべてのアセットを選択した場合、一致するクエリのツリー ブランチ全体を取得するために二次選択を行う必要があります。

したがって、最初のクエリの一致は次のようになります。

    4       4       suit_banker         3          april      texture

次に、CTE の後、完全な階層を取得し、結果は次のようになります (これまでのところ、これは機能しています)。

    3       3       suit               null        march      shape
    4       4       suit_banker         3          april      texture
   -5       6       tie_red             4          march      texture

id:-5 の親がそこにあることがわかりますが、欠落している必要があるのは、参照されているアセットと、参照されているアセットの親です。

    5       5       tie                null        march      shape
    6       6       tie_red             5          march      texture

現在、私のソリューションはこれで機能しますが、参照の深さは 1 つだけに制限されています (実装が非常に見苦しいと感じています)。

---編集済み---- これが私の主要な選択関数です。これは、本当の複雑さがどこにあるのかをよりよく示しているはずです: AssetReference.

Select A.id  as id, A.id as asset_id, A.name,A.parent_id as parent_id, A.subPath, T.name as typeName, A2.name as parent_name,  B.name as batchName, 
L.name as locationName,AO.owner_name as ownerName, T.id as typeID,
M.name as milestoneName, A.deleted as bDeleted, 0 as reference, W.phase_name, W.status_name
FROM Asset as A Inner Join Type as T on A.type_id = T.id
Inner Join Batch as B on A.batch_id = B.id
Left Join Location L on A.location_id = L.id
Left Join Asset A2 on A.parent_id = A2.id   
Left Join AssetOwner AO on A.owner_id = AO.owner_id
Left Join Milestone M on A.milestone_id = M.milestone_id
Left Join Workflow as W on W.asset_id = A.id
where A.deleted <= @showDeleted

UNION 

Select -1*AR.id as id, AR.asset_id as asset_id, A.name, AR.parent_id as parent_id, A.subPath, T.name as typeName, A2.name as parent_name,  B.name as batchName, 
L.name as locationName,AO.owner_name as ownerName, T.id as typeID,
M.name as milestoneName, A.deleted as bDeleted, 1 as reference, NULL as phase_name, NULL as status_name
FROM Asset as A Inner Join Type as T on A.type_id = T.id
Inner Join Batch as B on A.batch_id = B.id
Left Join Location L on A.location_id = L.id
Left Join Asset A2 on AR.parent_id = A2.id  
Left Join AssetOwner AO on A.owner_id = AO.owner_id
Left Join Milestone M on A.milestone_id = M.milestone_id
Inner Join AssetReference AR on AR.asset_id = A.id
where A.deleted <= @showDeleted

一時テーブル (#temp) を取得し、階層のすべての要素を検索するストアド プロシージャがあります。私が採用した戦略は次のとおりです。

  1. システム階層全体を選択して、各ツリー ブランチ全体のコンマ区切りリストで表される一時テーブル (#treeIDs) に入れます
  2. クエリに一致するアセットの階層全体を取得します (#temp から)
  3. Assets が指すすべての参照アセットを階層から取得する
  4. すべての参照アセットの階層を解析する

参照アセットは常にブランチの最後のアイテムであるため、これは今のところ機能しますが、そうでない場合は問題になると思います。より良い形の再帰が必要な気がします。

これは私の現在のコードです。これは機能していますが、私はそれを誇りに思っていません.

ステップ 1. 階層全体を構築する

;WITH Recursive_CTE AS (
 SELECT Cast(id as varchar(100)) as Hierarchy, parent_id, id
 FROM #assetIDs
Where parent_id is Null

UNION ALL

 SELECT
 CAST(parent.Hierarchy + ',' + CAST(t.id as varchar(100)) as varchar(100)) as Hierarchy, t.parent_id, t.id
 FROM Recursive_CTE parent
 INNER JOIN #assetIDs t ON t.parent_id = parent.id
)



Select Distinct h.id, Hierarchy as idList into #treeIDs
FROM ( Select Hierarchy, id FROM Recursive_CTE ) parent 
CROSS APPLY dbo.SplitIDs(Hierarchy) as h

ステップ 2. クエリに一致するすべてのアセットのブランチを選択する

Select DISTINCT L.id into #RelativeIDs FROM #treeIDs
CROSS APPLY dbo.SplitIDs(idList) as L
WHERE #treeIDs.id in (Select id FROM #temp)

ステップ 3. ブランチ内のすべての参照アセットを取得します (参照アセットには負の ID 値があるため、ID < 0 の部分)

Select asset_id  INTO #REFLinks FROM #AllAssets WHERE id in 
(Select #AllAssets.asset_id FROM #AllAssets Inner Join #RelativeIDs
 on #AllAssets.id = #RelativeIDs.id  Where #RelativeIDs.id < 0)

ステップ 4. ステップ 3 で見つかったすべてのブランチを取得する

Select DISTINCT L.id into #extraRelativeIDs FROM #treeIDs
CROSS APPLY dbo.SplitIDs(idList) as L
WHERE 
exists (Select #REFLinks.asset_id FROM #REFLinks WHERE #REFLinks.asset_id = #treeIDs.id) 
and Not Exists (select id FROM #RelativeIDs Where id = #treeIDs.id)

関連するコードだけを表示しようとしました。より良い解決策を見つけるのを手伝ってくれる人にとても感謝しています!

4

2 に答える 2