Tüm çocuklar için Toplam bulmak için özyinelemeli CTE


16

Aşağıda, beklenen sonuçlarla yinelenen bir T-SQLSorgu (muhtemelen CTE) kullanarak arama yapmak istediğim bir montaj ağacı . Herhangi bir bölümü verilen montaj başına toplam miktarı bilmek istiyorum.

Yani 'Perçin' ararsam, sadece doğrudan çocukların sayımı değil, meclisin her seviyesindeki toplam sayıyı bilmek istiyorum.

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

Şu anda, doğrudan ebeveynleri edinebilirim, ancak bu bilgileri yukarı doğru kaydırmama izin vermek için CTE'mi nasıl genişleteceğimi bilmek istiyorum.

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

Oluşturma komut dosyası

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)

Yanıtlar:


14

Bu özyinelemeli CTE ( SQL Fiddle ) örneğinizle çalışmalıdır:

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
;

Çıktı

ParentID    Count
1           6
2           3
3           2
4           1

Not: Yorumlarda, sorunun yalnızca basitleştirilmiş bir örnek tablo içerdiğini ve gerçek verilerin uygun dizinlere sahip olduğunu ve kopyaları ve verileri yeterince işlediğini söylediniz.

Kullanılan veriler ( 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)
;

Harika cevap teşekkür ederim! Bunu tüm Örnekler için [Meclis, Perçin vb.] Yinelemeli olarak yapmak kolay bir çözüm var mı?
greenhoorn

0

"Miktar" ve ne tablo (?) PartInstances ve sütunlar id ve sayım örnek gelen gelip ne anlama geldiğinden emin değilim ama örnek verilerinizden ne tahmin hesapladı.

;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

Umarım bu size bazı fikirler verir.

Güncelleme

Bunun bir test örneği olduğunu anlıyorum, ancak verileriniz başlangıçtan itibaren her şeyi kırıyor 1NF. Büyük olasılıkla tablonuz ikiye bölünmeli ve normalize edilmelidir.


Kodun ilk bölümündeki sonuçlara bakın .. bunlar istenir. 'Perçin' ararken, ağaçta herhangi bir parça verilen tüm perçinlerin toplamını almak istiyorum. Anlam instanceID 1 bana 6 sonucunu vermelidir. Yani tam ağaç yapısında toplam 6 perçin içerir.
markokstate
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.