CTE rekursif untuk menemukan Total untuk semua anak

16

Berikut adalah susunan pohon yang ingin saya cari menggunakan T-SQLKueri rekursif (mungkin CTE) dengan hasil yang diharapkan di bawah ini. Saya ingin tahu jumlah total per perakitan yang diberikan bagian mana pun.

Berarti jika saya mencari 'Rivet', saya ingin tahu jumlah total di setiap level dalam majelis, bukan hanya jumlah anak langsung.

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

Saat ini, saya bisa mendapatkan orang tua langsung, tetapi ingin tahu cara memperpanjang CTE saya untuk memungkinkan saya untuk menggulung informasi ini ke atas.

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

Script pembuatan

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)
markokstate
sumber

Jawaban:

14

CTE rekursif ini ( SQL Fiddle ) harus bekerja dengan sampel Anda:

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
;

Keluaran

ParentID    Count
1           6
2           3
3           2
4           1

Catatan: Anda menyebutkan dalam komentar bahwa pertanyaan hanya berisi tabel sampel yang disederhanakan dan data nyata memiliki indeks yang tepat dan menangani duplikat dan data secara memadai.

Data yang digunakan ( 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)
;
Julien Vavasseur
sumber
Jawaban yang bagus terima kasih! Apakah ada solusi mudah untuk melakukan ini secara rekursif untuk semua Mesin Virtual [Majelis, Paku Keling dll]?
greenhoorn
0

Saya tidak yakin saya mengerti apa yang Anda maksud dengan "jumlah" dan dari mana tabel (?) Bagian dan kolom id dan jumlah berasal dari sampel Anda, tetapi saya menghitung apa yang saya tebak dari data sampel Anda.

;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

Saya harap ini akan memberi Anda beberapa ide.

Memperbarui

Saya mengerti bahwa ini adalah contoh uji tetapi data Anda memecah semuanya mulai dari 1NF. Kemungkinan besar meja Anda harus dibagi dua dan dinormalisasi.

Alex Kudryashev
sumber
Lihat hasil di bagian pertama kode .. yang diinginkan. Saat mencari 'Rivet', saya mencari untuk mendapatkan total semua paku keling yang diberikan bagian di pohon. Berarti instanceID 1 harus memberi saya hasil dari 6. Berarti mengandung 6 paku keling total dalam struktur pohon lengkap itu.
markokstate