CTE ricorsivo per trovare Total per tutti i bambini


16

Ecco un albero di assemblaggio che voglio cercare usando una T-SQLquery ricorsiva (presumibilmente CTE) con i risultati previsti di seguito. Voglio sapere l'importo totale per assemblaggio dato qualsiasi parte.

Significa che se cerco 'Rivetto', voglio conoscere il conteggio totale ad ogni livello all'interno dell'assemblea, non solo il conteggio diretto dei figli.

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

Attualmente, posso ottenere i genitori diretti, ma voglio sapere come estendere il mio CTE per consentirmi di spostare queste informazioni verso l'alto.

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 di creazione

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)

Risposte:


14

Questo CTE ricorsivo ( SQL Fiddle ) dovrebbe funzionare con il tuo esempio:

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
;

Produzione

ParentID    Count
1           6
2           3
3           2
4           1

Nota: nei commenti hai menzionato che la domanda contiene solo una tabella di esempio semplificata e che i dati reali hanno indici adeguati e gestiscono duplicati e dati in modo adeguato.

Dati utilizzati ( 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)
;

Ottima risposta grazie! Esiste una soluzione semplice per farlo in modo ricorsivo per tutte le istanze [assemblaggio, rivetto, ecc.]?
Greenhoorn,

0

Io non sono sicuro di capire cosa si intende per "quantità" e dove da tavolo (?) PartInstances e le colonne id e contare provengono da nel campione, ma ho calcolato quello che presumo che dai dati del campione.

;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

Spero che questo ti dia alcune idee.

Aggiornare

Capisco che questo è un esempio di test, ma i tuoi dati interrompono tutto a partire da 1NF. Molto probabilmente il tuo tavolo dovrebbe essere diviso in due e normalizzato.


Vedi i risultati nella prima sezione del codice .. quelli sono desiderati. Durante la ricerca di 'Rivetto', sto cercando di ottenere un totale di tutti i rivetti dato qualsiasi pezzo nell'albero. Il significato di instanceID 1 dovrebbe darmi un risultato di 6. Significato che contiene 6 rivetti totali nella sua struttura ad albero completa.
markokstate,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.