以下は、再帰的なT-SQL
クエリ(おそらくCTE
)を使用して検索したいアセンブリツリーで、以下の期待される結果が得られます。任意の部品を与えられたアセンブリごとの合計金額を知りたいです。
つまり、「リベット」を検索すると、直接の子の数だけでなく、アセンブリ内の各レベルの総数も知りたいのです。
Assembly (id:1)
|
|-Rivet
|-Rivet
|-SubAssembly (id:2)
| |
| |-Rivet
| |-Bolt
| |-Bolt
| |-SubSubAssembly (id:3)
| |
| |-Rivet
| |-Rivet
|
|-SubAssembly (id:4)
|-Rivet
|-Bolt
DESIRED Results
-------
ID, Count
1 , 6
2 , 3
3 , 2
4 , 1
現在、直接の親を取得できますが、CTEを拡張してこの情報を上に上げる方法を知りたいです。
With DirectParents AS(
--initialization
Select InstanceID, ParentID
From Instances i
Where i.Part = 'Rivet'
UNION ALL
--recursive execution
Select i.InstanceID, i.ParentID
From PartInstances i INNER JOIN DirectParents p
on i.ParentID = p.InstanceID
)
select ParentID, Count(instanceid) as Totals
from DirectParents
group by InstanceID, ParentID
Results
-------
ID, Count
1 , 2
2 , 2
3 , 2
4 , 1
作成スクリプト
CREATE TABLE [dbo].[Instances] (
[InstanceID] NVARCHAR (50) NOT NULL,
[Part] NVARCHAR (50) NOT NULL,
[ParentID] NVARCHAR (50) NOT NULL, );
INSERT INTO Instances
Values
(1, 'Assembly', 0),
(50, 'Rivet', 1),
(50, 'Rivet', 1),
(2, 'SubAssembly', 1),
(50, 'Rivet', 2),
(51, 'Bolt', 2),
(51, 'Bolt', 2),
(3, 'SubSubAssembly', 2),
(50, 'Rivet', 3),
(50, 'Rivet', 3),
(4, 'SubAssembly2', 1),
(50, 'Rivet', 4),
(51, 'Bolt', 4)
この再帰CTE( SQL Fiddle )はサンプルで機能するはずです。
WITH cte(ParentID) AS(
SELECT ParentID FROM @Instances WHERE [Part] = 'Rivet'
UNION ALL
SELECT i.ParentID FROM cte c
INNER JOIN @Instances i ON c.ParentID = i.InstanceID
WHERE i.ParentID > 0
)
SELECT ParentID, count(*)
FROM cte
GROUP BY ParentID
ORDER BY ParentID
;
ParentID Count
1 6
2 3
3 2
4 1
注:質問には簡略化されたサンプルテーブルのみが含まれており、実際のデータには適切なインデックスがあり、重複やデータを適切に処理することがコメントで述べられています。
使用データ( SQL Fiddle ):
DECLARE @Instances TABLE(
[InstanceID] int NOT NULL
, [Part] NVARCHAR (50) NOT NULL
, [ParentID] int NOT NULL
);
INSERT INTO @Instances([InstanceID], [Part], [ParentID])
VALUES
(1, 'Assembly', 0)
, (50, 'Rivet', 1)
, (50, 'Rivet', 1)
, (2, 'SubAssembly', 1)
, (50, 'Rivet', 2)
, (51, 'Bolt', 2)
, (51, 'Bolt', 2)
, (3, 'SubSubAssembly', 2)
, (50, 'Rivet', 3)
, (50, 'Rivet', 3)
, (4, 'SubAssembly2', 1)
, (50, 'Rivet', 4)
, (51, 'Bolt', 4)
;
「amount」の意味と、テーブル(?)PartInstancesと列idとcountがどこから来たのかがわかりませんあなたのサンプルですが、私はあなたのサンプルデータから私が推測するものを計算しました。
;with ins as (
select [InstanceID], [Part],[ParentID],0 lvl
from instances where ParentID=0
union all
select i.[InstanceID], i.[Part],i.[ParentID], lvl+1
from instances i
inner join ins on i.parentid=ins.InstanceID
)
select InstanceID,part,COUNT(*) cnt
from ins
group by instanceid,part
これがあなたにいくつかのアイデアを与えることを願っています。
これはテストの例であることを理解していますが、あなたのデータは1NF
。ほとんどの場合、テーブルは2つに分かれて正規化されているはずです。