Newsgroup: it.comp.appl.access
Titolo: Ricostruzione Albero Categorie

Buongiorno a tutti,
dovrei ricostruire, su un unico record, tutta la dipendenza tra categorie e sottocategorie partendo da una tabella già esistente.
Questa tabella è così composta, riporto solo i campi salienti:
 
Id Ctg Art - Numerico
Desc Ctg - Testo
Id nodo - Numerico
(nomi dei campi con spazi....mah!!!)
 
i dati sono così inseriti
 
1 - Grandi Elettrodomestici - 0
3 - Piccoli Elettrodomestici - 0
15 - Incasso - 0
7 - Conservazione - 1
35 - Lavaggio e asciugatura - 1
18 - Frigoriferi - 7
44 - Frigoriferi - 7
32 - Doppia Porta - 18
82 - Mono Porta - 44
 
ecc... ecc..
 
Come potete vedere le categorie principali (quelle con 0) si "legano" alle sottocategorie tramite l'Id nodo. Siccome con le sottocategorie si scende anche di 3/4 livelli... la domanda è, come posso mettere in un solo record, tutto l'albero partendo dalla categoria principale? Quello che devo ottenere è qualcosa di simile:
 
1;Grandi Elettrodomestici;Conservazione;Frigoriferi;Doppia Porta
1;Grandi Elettrodomestici;Conservazione;Frigoriferi;Mono Porta
ecc
ecc
 
Non riesco a venirne a capo, qualche idea? 
 
Grazie
Alfio
 

Alfio presented the following explanation :

Chiama Categorie la tabella che contiene [Id Ctg Art],
[Desc Ctg] e [Id nodo].
 
Metti da qualche parte le due sub che seguono ed esegui la prima.
==============================================
Public Sub CTG()
Dim db As Database, RS As Recordset, h, i, j, k, SQL As String
Dim ID As Integer, S As String, RS_C As Recordset
 
Set db = CurrentDb
 
SQL = "SELECT Categorie.[Id nodo], Categorie.[Id Ctg Art] "
SQL = SQL & "From Categorie WHERE (((Categorie.[Id nodo]) = 0)) "
SQL = SQL & "ORDER BY Categorie.[Id Ctg Art];"
Set RS_C = db.OpenRecordset(SQL, dbOpenDynaset)
 
Do Until RS_C.EOF
    SQL = "SELECT Categorie.[Id nodo], Categorie.[Desc Ctg], 
Categorie.[Id Ctg Art] "
    SQL = SQL & "From Categorie WHERE (((Categorie.[Id nodo]) = 0) "
    SQL = SQL & "And Categorie.[Id Ctg Art] = " & RS_C![Id Ctg Art] & 
") "
    SQL = SQL & "ORDER BY Categorie.[Id Ctg Art];"
    Set RS = db.OpenRecordset(SQL, dbOpenDynaset)
    Do Until RS.EOF
        ID = RS![Id Ctg Art]
        S = RS![Id Ctg Art]
        Call CTG_S(ID, S)
        RS.MoveNext
    Loop
    RS_C.MoveNext
Loop
 
End Sub
========================================================
 
========================================================
Public Sub CTG_S(ID As Integer, ByVal S As String)
Dim SQL As String, RS As Recordset, db As Database, SS As String
 
SS = S
Set db = CurrentDb
SQL = "SELECT Categorie.[Id nodo], Categorie.[Desc Ctg], Categorie.[Id 
Ctg Art] "
SQL = SQL & "From Categorie WHERE (((Categorie.[Id nodo]) = " & ID & 
")) "
SQL = SQL & "ORDER BY Categorie.[Id Ctg Art];"
Set RS = db.OpenRecordset(SQL, dbOpenDynaset)
Do Until RS.EOF
    ID = RS![Id Ctg Art]
    S = SS & " - " & ID
    MsgBox S
    Call CTG_S(ID, S)
    RS.MoveNext
    S = SS
Loop
 
End Sub
==================================================
 
Bruno

Grazie Bruno, vado a provarle subito!!! :)))
Ti faccio sapere...

 
 
Posso chiederti una cortesia?
Quanto tempo ci mette e quanti record ci sono sulla tabella?
 
-- 
ac (x=y-1)
Aborro il Killfile
(La violenza e' l'ultimo rifugio degli incapaci -Salvor Hardin-)

La ricorsione.... questa sconosciuta...
 
Saranno 20... 25 i records...
 
;-)
 
@Alex

Ciao, è molto veloce, si tratta di db di un grossista, poche voci molte quantità. Il totale dei record sono 582, un po' più di 25... :)
 
Alfio

Alfio se hai una gestione gerarchica multilivello non puoi scrivere funzioni con livelli fissi definiti... 
Di solito chi gestisce una gerarchia Multilivello dove non è dato un limite,scrive funzioni ricorsiva in quanto non ci si deve preoccupare del livello.
 
Questo metodo è perfettamente in linea con l'oggetto gerarchico per eccellenza: IL TREEVIEW.
 
Per scrivere funzioni ricorsiva però serve avere più puntiglio nella stesura del codice per non incappare nell'esaurimento dello stack.
Ci sono poi altri accorgimenti da usare che sono sempre delle opportunità... esempio se si apre un recordset solo per leggere i dati e popolare il treeview lo si apre come Snapshot in quanto risulta più rapido.
 
Per chiarezza se cerchi su google.come popolare un Treeview trovi solo funzioni ricorsive che possono darti una visione più funzionale.
 
Saluti
@Alex

Mille grazie Bruno, funziona perfettamente.
 
Alfio

Alfio 500 record e 25 è la stessa cosa...
Se inizi ad avere qualche decina di migliaia di records allora nascono problemi che ti costringono a fare le cose in modo diverso.
 
In ogni caso buon lavoro.
 
@Alex

Grazie Alex, lo farò senz'altro.
 
Alfio

Immagino Alex, ma la tabella fa parte di un gestionale che non ho creato io. Purtroppo il gestionale in questione non avendo una realizzazione di listino molto funzionale devo intervenire esternamente e ho (avevo...) bisogno della ricostruzione gerarchica delle categorie...


Ehila! /vecchio/ AB!
Sempre sul pezzo!
;-)


 
 
Grazie Alfio.
Molto veloce, quanto? Non fai in tempo a dare invio e' gia' ha risposto? ;-)


No no ora faccio Pizze... pensavo anche ai cannoli... ma la concorrenza è spietata soprattutto qui in ICAA.
 
Saluti.
 
@Alex

 Alfio
 
Già che c'ero ho messo in tabella i risultati
[Id Ctg Art] e [Desc Ctg]... così assomiglia di più a un albero.
 
Bruno

 
 
ICAA lo leggo spesso (basta un click).
E mi sento molto ignorante.
Vedo invece che /spesso/ vinci a mani basse in /surplace/ ,si
sarebbe detto una volta.
Ora ogni tanto (spesso) /pontifico/ su ILI ma + di un /COGLIONE/ non 
rimedio ;-)


 ;-)
 
E dici poco!
A rimediar coglioni
si vincon l'elezioni.
 
Bruno


Azz! Allora anch'io vincero' a mani basse! ;-)


 
...praticamente

 Non riesco a venirne a capo, qualche idea?
 
E' sufficiente una sola istruzione sql:
 
1) Mi creo la tabella :
 
declare @Samples as Table ( IdCtgArt Int, DescCtg VarChar(32), IdNodo Int );
insert into @Samples ( IdCtgArt, DescCtg, IdNodo ) values
   ( 1, 'GRANDI ELETTRODOMENSTICI', 0 ),
   ( 3, 'PICCOLI ELETTRODOMESTICI', 0 ),
   ( 15, 'INCASSO', 0 ),
   ( 7, 'CONSERVAZIONE', 1 ),
   ( 35, 'Lavaggio e asciugatura', 1 ),
   ( 18, 'Frigoriferi', 7 ),
   ( 44, 'Frigoriferi', 7 ),
   ( 32, 'DOPPIA PORTA', 18 ),
   ( 82, 'MONO PORTA', 44 );
--select * from @Samples;
 
 
 
 
2) Comando SQL :
 
with
   LeafNodes as (
     -- Ottengo le foglie
     select IdCtgArt, DescCtg, IdNodo
       from @Samples as SP
       where not exists ( select 42 from @Samples as SC where SC.IdNodo 
= SP.IdCtgArt ) ),
   Tree as (
     -- inizio con le foglie
     select IdCtgArt, DescCtg, IdNodo, IdCtgArt as LeafId, 0 as Depth, 
Cast( DescCtg as VarChar(1024) ) as Path
       from LeafNodes as LN
     union all
     -- risalgo la gerarchia
     select S.IdCtgArt, S.DescCtg, S.IdNodo, T.LeafId, T.Depth + 1, 
Cast( S.DescCtg + ', ' + T.Path as VarChar(1024) )
       from Tree as T inner join
         @Samples as S on S.IdCtgArt = T.IdNodo
     ),
   InterestingRows as (
 
     select LeafId, Max( Depth ) as MaxDepth
       from Tree as T
       where T.LeafId in ( select IdCtgArt from LeafNodes )
       group by LeafId )
 
   select T.IdCtgArt, T.Path
     from Tree as T inner join
       InterestingRows as IR on IR.LeafId = T.LeafId and IR.MaxDepth = 
T.Depth
     where T.Depth > 0;
 
 
Ottengo:
1	GRANDI ELETTRODOMENSTICI, CONSERVAZIONE, Frigoriferi, MONO PORTA
1	GRANDI ELETTRODOMENSTICI, CONSERVAZIONE, Frigoriferi, DOPPIA PORTA
 
etc..
 

 No no ora faccio Pizze... pensavo anche ai cannoli... ma la concorrenza è spietata soprattutto qui in ICAA.
 
Già!
ti toccherà migrare al sud ;-)
 
Ciao Bello :-)
 
Daniele

Mi chiedevo quando saresti saltato fuori... invece escono solo Pizzaioli DOCG  
 
;-)
 
Ciao ragazzo.
@Alex