Sistemare dati grezzi in tabella



  • Sistemare dati grezzi in tabella
    di MarcoSpa data: 28/06/2017 10:01:01

    Buongiorno a tutti,
    Sono nuovo del forum ho provato a vedere nelle discussioni vecchie ma non trovo quella che fa per me.
    Avrei bisogno di mettere a posto dei dati grezzi attualmente su due colonne per circa 110k righe in diverse colonne con un operazione trasponi parziale. con un esempio mi spiego meglio.
    Il file si presenta + o - così:
    nome tizio
    cognome caio
    stato sempronio
    colore blu
    indirizzo via
    indirizzo roma
    indirizzo 13
    dati alto
    dati basso
    dati largo
    nome remo
    cognome rossi
    stato vedovo
    colore giallo
    colore verde
    indirizzo via
    indirizzo galileo
    indirizzo 8
    indirizzo milano
    dati ruvido
    dati liscio
    dati caldo
    dati freddo
    dati pesante
    ecc...

    Trasformare come segue:
    nome;cognome;stato;colore1;colore2;indirizzo1;indirizzo2;indirizzo3;indirizzo4;dati1;dati2;dati3;dati4;dati5
    tizio;caio;sempronio;blu;;via ;roma;13;;alto;basso;largo;;
    remo;rossi;vedovo;giallo;verde;via ;galileo;8;milano;ruvido;liscio;caldo;freddo;pesante

    i campi si ripetono sempre, solo che a volte occupano più righe.Per es. "dati" del cliente Tizio Caio è 3 righe mente "dati" di Remo Rossi è 5 righe, quindi alla fine della sistemazione dovrei avere un numero di colonne per "dati" pari al numero max di righe che trovo in tutto il file di origine.

    Forse dovrei usare una macro, ma non sono pratico.




  • di Vecchio Frac data: 28/06/2017 10:17:19

    cit. "Forse dovrei usare una macro, ma non sono pratico."
    ---> Senza "forse" bisogna però capire se il tuo livello di "praticità" ha speranze di essere incrementato perchè altrimenti poi non sarai in grado di manutenere o modificare il codice per eventuali nuove esigenze.





  • di MarcoSpa data: 28/06/2017 18:39:08

    La mia esperienza di macro è che quando ne trovo una che mi serve cerco di adattarla alle mie esigenze, ma non ne ho mai scritta una ex novo
    Quindi dici che con semplici funzioni non ce la faccio è che non riesco a capire che logica usare.



  • di Vecchio Frac data: 29/06/2017 08:45:53

    Per capire che logica devi usare ti basta un foglio di carta e una matita.
    Pensa a come risolveresti il problema se dovessi farlo a mano su un foglio.
    Scrivi in italiano (anche stringato: si chiama pseudocodice) i passi necessari per la soluzione, che tengano conto di eventuali problemi collaterali da spezza in più sottoproblemi.
    Poi trasporre questa descrizione in una cosa eseguibile è solo questione di scelta del linguaggio di programmazione e della sua corretta sintassi.






  • di Vecchio Frac data: 29/06/2017 15:20:33

    Nessuna idea?
    Ammetto però che era un po' incasinato ^_^
     
    Option Explicit
    
    Sub transform()
    Dim i As Long, j As Long, ur As Long
    Dim ri As Long, u As Long
    Dim indice_colore As Integer, indice_indirizzo As Integer, indice_dati As Integer
    Dim maxc As Long, maxi As Long, maxd As Long
    
        ur = Range("A1").CurrentRegion.Rows.Count
        
        ri = 1:    i = 1
        [e1] = "nome":    [f1] = "cognome":    [g1] = "stato"
            
        For i = 1 To ur
            If Cells(i, "A") = "nome" Then
                j = i
                ri = ri + 1
                Cells(ri, "E") = Cells(i, "B")
                indice_colore = 0
                indice_indirizzo = 0
                indice_dati = 0
            Else
                j = j + 1
                
                Select Case Cells(i, "A")
                Case "cognome"
                    Cells(ri, "F") = Cells(i, "B")
    
                Case "stato"
                    Cells(ri, "G") = Cells(i, "B")
    
                Case "colore":
                    indice_colore = indice_colore + 1
                    u = 7 + indice_colore
                    If indice_colore > maxc Then
                        maxc = indice_colore
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "colore" & indice_colore
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "indirizzo"
                    indice_indirizzo = indice_indirizzo + 1
                    u = 7 + indice_colore + indice_indirizzo
                    If indice_indirizzo > maxi Then
                        maxi = indice_indirizzo
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "indirizzo" & indice_indirizzo
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "dati"
                    indice_dati = indice_dati + 1
                    u = 7 + indice_colore + indice_indirizzo + indice_dati
                    If indice_dati > maxd Then
                        maxd = indice_dati
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "dati" & indice_dati
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                End Select
            End If
            i = j
         Next
        
        MsgBox "Done."
    End Sub
    






  • di MarcoSpa data: 03/07/2017 11:34:07

    Ciao Vecchio Frac,
    Ti avevo risposto ma forse con la chiusura della discussione non sono stato pubblicato, ci riprovo.
    GRAZIE MILLE!! Sono commosso dalla potenza della tua soluzione, che era decisamente fuori dalla mia portata!
    Io avevo provato a metter su carta il meccanismo, solo che rispetto al tuo era più complicato, nel senso che io volevo far si che la macro individuasse i "case" in automatico con un "CERA VERT" e poi inizializzasse un numero di colonne per ogni "case" uguale al "MAX" dei "CONTA" di ogni "case"..
    Insomma ero allo stesso tempo ARENATO e IN ALTO MARE..

    Ancora Grazie.
    Marco



  • di Vecchio Frac data: 03/07/2017 11:47:32

    Bene, pro futuro tieni conto che quando devi studiare un algoritmo non devi ancora pensare al codice vero e proprio, devi solo descrivere i passaggi che faresti fare a qualcuno che non sa niente del tuo problema (sia umano o computer). Passaggi complicati possono essere suddivisi in blocchi più piccoli. Poi testi il risultato. Se funziona lo traduci in codice. Che poi va migliorato e corretto a sua volta :)
    Magari la tua soluzione era anche più performante della mia (che banalmente inserisce una colonna ogni volta che trova un indice in più della categoria richiesta). Inoltre ricordati di analizzare bene lo scenario (per esempio non l'avevi detto, ma l'ho intuito dall'esempio, che i primi tre campi erano fissi: nome, cognome e stato).
    E poi se sei arenato in alto mare (ossimoro un po' curioso ^_^) puoi sempre chiedere aiuto :)

    ps non è fuori della tua portata, è un semplice ciclo For con dentro un If che analizza delle intestazioni di colonna e inserisce una colonna al momento giusto.





  • di MarcoSpa data: 03/07/2017 12:00:17

    cit: Magari la tua soluzione era anche più performante della mia..
    Il fatto è che il segreto della risoluzione dei problemi è avere due cose: immaginazione e capacità di semplificazione... e questa volta sono stato carente in entrambe.
    la prossima volta non mi lascerò sconfortare!



  • di MarcoSpa data: 04/07/2017 11:08:43

    Ho modificato il tuo codice, e ho provato a cavarmela da solo, ma ho un piccolo ostacolo che non riesco a superare.
    Quando vengono aggiunte le colonne questa operazione funziona solo per la singola riga e non per tutte, forse è il ciclo “for” che ho modificato?
    A dire il vero con i dati che avevo mandato il tuo codice funziona come vorrei per le prime due righe, ma dopo la mia modifica per adattarlo al caso reale devo aver incasinato qualcosa e non funziona più.
    Incollo un po di dati perché non so come mendare un file e qui sotto il codice commentato così, se qualcuno ha voglia e tempo, mi dice dove l'ho incasinato o cosa non ho capito.
    Rif_RiGa;794642
    Rif_Gara;11376971794642
    Ente_app;Unione Dei Comuni Bassa Reggiana Di Novellara
    Ente_app;Piazzale Marconi N. 1
    Ente_app;42017 Novellara (re)
    Ogg;Costituzione Dell'elenco Degli Operatori Economici.
    Cdz_econom;NS
    Importo;0
    Durata;959 giorni
    Oneri;0
    Onorario;0
    Procedura;Ns
    Articolo;Ns
    Data_Ins;16/02/2015 
    Aggiornam;16/02/2015 
    Data_aggiudica;
    Zone;Novellara (RE)
    Cat;T-AF
    Cat;M-OG1
    Cat;M-OG2
    Cat;M-OG3
    Cat;M-OG4
    Cat;M-OG5
    Cat;M-OG6
    Cat;M-OG7
    Cat;M-OG8
    Cat;M-OG9
    Cat;M-OG10
    Aggiudicatario;315572 - VINCITORE NON COMPLETO PER MANCANZA DI INDIRIZZO - VEDASI FONTE ESITO , - - -
    Aggiudicatario;- Vincitore: Vedasi Fonte Esito Allegata;
    Rif_RiGa;805725
    Rif_Gara;11550812
    Ente_app;Provincia Di Padova - Stazione Unica Appaltante - Comune Di Solesino
    Ente_app;Piazza Bardella N. 2/3
    Ente_app;35131 Padova (pd)
    Ogg;Cig 615550536b. Servizio Di Pulizia Locali Comunali Della Sede Municipale Del Comune Di Solesino, Per Il Periodo Maggio 2015/aprile 2018. Importo Complessivo Di Euro 81.000,00.
    Cdz_econom;PUNTI 82.00
    Importo;81.000,00
    Durata;3_anni
    Oneri;0
    Onorario;0
    Procedura;Avviso Di Manifestazione D'interesse
    Articolo;Offerta Economicamente Piu' Vantaggiosa, Art.83 D.lgs. 163/06, Art.125 Comma 11 D.lgs. 163/06
    Data_Ins;25/06/2015 
    Aggiornam;29/06/2015 
    Data_aggiudica;
    Zone;Solesino (PD)
    Cat;F-IGIS
    Aggiudicatario;532244 - COOPERATIVA SOCIALE BLU SOC. COOP. ONLUS, VIA FACCIOLATI 112/B - - PADOVA - PD
    Aggiudicatario;- 29/06/15: L'avviso Viene Riproposto Per Aggiornam Fonte (aggiudicazione Definitiva);
    Rif_RiGa;794200
    Rif_Gara;11497256
    Ente_app;Altavita Istituzioni Riunite Di Assistenza Ira Di Padova
    Ente_app;Piazzale Mazzini N. 14
    Ente_app;35137 Padova (pd)
    Ogg;Cig 5903795dbe. Affidamento Del Servizio Di Lavanderia. L'appalto Riguarda Il Servizio Di Noleggio, Lavaggio E Stiratura Della Biancheria Piana E Delle Divise Per Il Personale E, Inoltre, Il Lavaggio E La Stiratura Della Biancheria Degli Ospiti E Di Proprieta' Dell'ente. Importo Complessivo Di Euro 4.456.332,50 Di Cui Euro 2.500,00 Per Oneri Di Sicurezza Non Soggetti A Ribasso D'asta.
    Cdz_econom;Importo netto 3.263.541,00
    Importo;4.456.332,50
    Durata;60 mesi
    Oneri;2.500,00
    Onorario;0
    Procedura;Pubblico Incanto
    Articolo;Offerta Economicamente Piu' Vantaggiosa
    Data_Ins;11/02/2015 
    Aggiornam;11/02/2015 
    Data_aggiudica;27/01/2015 
    Zone;Selvazzano Dentro (PD)
    Cat;T-SANITA
    Cat;F-TESS
    Aggiudicatario;491887 - COOPERATIVA SOCIALE EUREKA, VIA PER SALVATRONDA 27/A - 31033 - CASTELFRANCO VENETO - TV
    Rif_RiGa;793215
    Rif_Gara;11379604
    Ente_app;Autostrada Brescia Verona Vicenza Padova Spa
    Ente_app;Via Flavio Gioia N. 71
    Ente_app;37100 Verona (vr)
    Ogg;Riaffidamento Dei Servizi Di Distribuzione Carbolubrificanti (in Seguito oil) E Delle Attivita' Ristorative E Commerciali (in Seguito non Oil), Da Svolgersi Nelle Aree Di Servizio (in Seguito a.di S.) E Nelle Aree Di Sosta (in Seguito a.di So.) Ubicate Lungo Le Predette Tratte Autostradali. Servizio Oil Servizio Non Oil Aree Di Servizio E Di Sosta Delle Tratte Autostradali A4 Brescia Verona Vicenza Padova A31 Valdastico Nord. Lotto 26 Area Di Sosta Villa Morosini Ovest A4 Km 325+400. Tipologia Del Servizio: Non Oil.
    Cdz_econom;NS
    Importo;0
    Durata;5 anni
    Oneri;0
    Onorario;0
    Procedura;Avviso Di Manifestazione D'interesse
    Articolo;Ns
    Data_Ins;02/02/2015 
    Aggiornam;02/02/2015 
    Data_aggiudica;
    Zone;Padova (PD)
    Cat;F-ALISE
    Cat;F-GES
    Aggiudicatario;357476 - ANNULLATA
    Rif_RiGa;791442
    Rif_Gara;11491235
    Ente_app;Altavita Istituzioni Riunite Di Assistenza Ira Di Padova
    Ente_app;Piazzale Mazzini N. 14
    Ente_app;35137 Padova (pd)
    Ogg;Servizio Di Ristorazione Per Le Strutture Di Altavita-istituzioni Riunite Di Assistenza - Ira. Importo Complessivo Di Euro 6.000.000,00 Di Cui Euro 7.500,00 Per Oneri Di Sicurezza Non Soggetti A Ribasso D'asta.
    Cdz_econom;NS
    Importo;6.000.000,00
    Durata;5 anni
    Oneri;7.500,00
    Onorario;0
    Procedura;Procedura Negoziata
    Articolo;Ns
    Data_Ins;14/01/2015 
    Aggiornam;14/01/2015 
    Data_aggiudica;
    Zone;Padova (PD)
    Cat;T-SANITA
    Cat;F-ALISE
    Aggiudicatario;485713 - SODEXO ITALIA S.P.A., - - CINISELLO BALSAMO - MI
    Aggiudicatario;- Aggiudicazione Definitiva;
    Rif_RiGa;791877
    Rif_Gara;11086380
    Ente_app;Ausl Azienda Unita' Sanitaria Locale N 16
    Ente_app;Via Degli Scrovegni N. 14
    Ente_app;35100 Padova (pd)
    Ogg;Servizio Di Lavanoleggio Di Divise, Biancheria Piana E Confezionata, Comprensivo Di Materasseria Da Effettuare Nell'ambito Dell'area Vasta Di Padova. Importo Complessivo Di Euro 36.096.303,00 Iva Esclusa.
    Cdz_econom;Importo netto 8.462.339,30
    Importo;12.981.423,00
    Durata;72 mesi
    Oneri;0
    Onorario;0
    Procedura;Ristretta
    Articolo;Offerta Economicamente Piu' Vantaggiosa
    Data_Ins;19/01/2015 
    Aggiornam;19/01/2015 
    Data_aggiudica;27/11/2014 
    Zone;Padova (PD)
    Cat;T-SANITA
    Cat;F-TESS
    Aggiudicatario;221977 - LAVANDERIA INDUSTRIALE CIPELLI S.R.L., VIA CASCINETTA N. 12 - 26812 - BORGHETTO LODIGIANO - MI
    Aggiudicatario;- A.t.i.; - Associato: Ata Imbottiti; - Lotto 1
    Rif_RiGa;791878
    Rif_Gara;11086380
    Ente_app;Ausl Azienda Unita' Sanitaria Locale N 16
    Ente_app;Via Degli Scrovegni N. 14
    Ente_app;35100 Padova (pd)
    Ogg;Servizio Di Lavanoleggio Di Divise, Biancheria Piana E Confezionata, Comprensivo Di Materasseria Da Effettuare Nell'ambito Dell'area Vasta Di Padova. Importo Complessivo Di Euro 36.096.303,00 Iva Esclusa.
    Cdz_econom;Importo netto 15.055.066,08
    Importo;23.114.880,00
    Durata;72 mesi
    Oneri;0
    Onorario;0
    Procedura;Ristretta
    Articolo;Offerta Economicamente Piu' Vantaggiosa
    Data_Ins;19/01/2015 
    Aggiornam;19/01/2015 
    Data_aggiudica;27/11/2014 
    Zone;Padova (PD)
    Cat;T-SANITA
    Cat;F-TESS
    Aggiudicatario;221977 - LAVANDERIA INDUSTRIALE CIPELLI S.R.L., VIA CASCINETTA N. 12 - 26812 - BORGHETTO LODIGIANO - MI
    Aggiudicatario;- A.t.i.; - Associato: Ata Imbottiti; - Lotto 2

     
    Option Explicit
    
    Sub transform1()
    'prima parte di dichiarazione delle variabili
    Dim i As Long, j As Long, ur As Long
    Dim ri As Long, u As Long
    Dim indice_Ente_app As Integer, indice_Ogg As Integer, indice_Cdz_econom As Integer, indice_Importo As Single, indice_Durata As Integer, indice_Oneri As Integer, indice_Onorario As Integer, indice_Procedura As Integer, indice_Articolo As Integer, indice_Data_Ins As Integer, indice_Aggiornam As Integer, indice_Data_aggiudica As Integer, indice_Zone As Integer, indice_Cat As Integer, indice_Aggiudicatario As Integer
    'maxc, maxi, maxd, ecc sono nomi di variabili o il prefisso max ha qualche funzione?
    Dim maxc As Long, maxi As Long, maxd As Long, maxh As Long, maxj As Long, maxk As Long, maxl As Long, maxm As Long, maxn As Long, maxo As Long, maxp As Long, maxq As Long, maxr As Long, maxs As Long, maxt As Long, maxu As Integer
    
        ur = Range("A1").CurrentRegion.Rows.Count
        ' non riesco a tradurre/capire quanto sopra.. individua l'area dove c'è la cella selezionata?
        
        ri = 1:    i = 1
        [e1] = "Rif_RiGa":    [f1] = "Rif_Gara"
        
        For i = 1 To ur 'per i che va da 1 a ur
            If Cells(i, "A") = "Rif_RiGa" Then  'se le celle i-esime nella Colonna A sono “Rif_Riga” allora
                j = i   'j diventa i
                ri = ri + 1 'ri aumenta di 1
                Cells(ri, "E") = Cells(i, "B")  'le celle ri-esime della colonna E sono uguali alle celle i-esime della colonna B
                indice_Ente_app = 0 'indice_Ente_app da zero
                indice_Ogg = 0
                indice_Cdz_econom = 0
                indice_Importo = 0
                indice_Durata = 0
                indice_Oneri = 0
                indice_Onorario = 0
                indice_Procedura = 0
                indice_Articolo = 0
                indice_Data_Ins = 0
                indice_Aggiornam = 0
                indice_Data_aggiudica = 0
                indice_Zone = 0
                indice_Cat = 0
                indice_Aggiudicatario = 0
    
            Else    'altrimenti (l’ ”else” praticamente divide i casi tra le categorie che hanno solo una colonna da quelle che possono avere più colonne giusto?)
                j = j + 1
                
                Select Case Cells(i, "A")    'selezione dei casi nelle celle i-esime della colonna A
                Case "Rif_Gara"     'caso "Rif_Gara"
                    Cells(ri, "F") = Cells(i, "B")  'le celle ri-esime della colonna F sono uguali alle celle i-esime della colonna B
    
                Case "Ente_app":    'caso "Ente_app"
                    indice_Ente_app = indice_Ente_app + 1   'l'inice Ente_app si incrementa di 1
                    u = 6 + indice_Ente_app 'u parte da 6+1. u è la colonna dove scrivo il dato di "B" relativo al caso in esame che aumenta con i casi e le colonne dei casi?
                    If indice_Ente_app > maxc Then  'se indice_Ente_app > maxc allora uguaglia indice_Ente_app e maxc ???
                        maxc = indice_Ente_app
                        Cells(1, u).EntireColumn.Insert xlShiftToRight 'la cella (riga 1, colonna u) inserire una colonna a destra
                        Cells(1, u) = "Ente_app" & indice_Ente_app  'l'intestazione di colonna è: "Ente_App(indice_Ente_app)"
                    End If
                    Cells(ri, u) = Cells(i, "B") 'inserisci il valore nella cella prendendolo dalla relativa posizione nella colonna B
    
                Case "Ogg"
                    indice_Ogg = indice_Ogg + 1
                    u = 6 + indice_Ente_app + indice_Ogg
                    If indice_Ogg > maxi Then
                        maxi = indice_Ogg
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Ogg" & indice_Ogg
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Cdz_econom"
                    indice_Cdz_econom = indice_Cdz_econom + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom
                    If indice_Cdz_econom > maxd Then
                        maxd = indice_Cdz_econom
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Cdz_econom" & indice_Cdz_econom
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Importo"
                    indice_Importo = indice_Importo + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo
                    If indice_Importo > maxh Then
                        maxh = indice_Importo
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Importo" & indice_Importo
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Durata"
                    indice_Durata = indice_Durata + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata
                    If indice_Durata > maxj Then
                        maxj = indice_Durata
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Durata" & indice_Durata
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Oneri"
                    indice_Oneri = indice_Oneri + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri
                    If indice_Oneri > maxk Then
                        maxk = indice_Oneri
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Oneri" & indice_Oneri
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Onorario"
                    indice_Onorario = indice_Onorario + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario
                    If indice_Onorario > maxl Then
                        maxl = indice_Onorario
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Onorario" & indice_Onorario
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Procedura"
                    indice_Procedura = indice_Procedura + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura
                    If indice_Procedura > maxm Then
                        maxm = indice_Procedura
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Procedura" & indice_Procedura
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Articolo"
                    indice_Articolo = indice_Articolo + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo
                    If indice_Articolo > maxn Then
                        maxn = indice_Articolo
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Articolo" & indice_Articolo
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Data_Ins"
                    indice_Data_Ins = indice_Data_Ins + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo + indice_Data_Ins
                    If indice_Data_Ins > maxo Then
                        maxo = indice_Data_Ins
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Data_Ins" & indice_Data_Ins
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Aggiornam"
                    indice_Aggiornam = indice_Aggiornam + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo + indice_Data_Ins + indice_Aggiornam
                    If indice_Aggiornam > maxp Then
                        maxp = indice_Aggiornam
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Aggiornam" & indice_Aggiornam
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Data_aggiudica"
                    indice_Data_aggiudica = indice_Data_aggiudica + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo + indice_Data_Ins + indice_Aggiornam + indice_Data_aggiudica
                    If indice_Data_aggiudica > maxq Then
                        maxq = indice_Data_aggiudica
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Data_aggiudica" & indice_Data_aggiudica
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Zone"
                    indice_Zone = indice_Zone + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo + indice_Data_Ins + indice_Aggiornam + indice_Data_aggiudica + indice_Zone
                    If indice_Zone > maxr Then
                        maxr = indice_Zone
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Zone" & indice_Zone
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Cat"
                    indice_Cat = indice_Cat + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo + indice_Data_Ins + indice_Aggiornam + indice_Data_aggiudica + indice_Zone + indice_Cat
                    If indice_Cat > maxt Then
                        maxt = indice_Cat
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Cat" & indice_Cat
                    End If
                    Cells(ri, u) = Cells(i, "B")
    
                Case "Aggiudicatario"
                    indice_Aggiudicatario = indice_Aggiudicatario + 1
                    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom + indice_Importo + indice_Durata + indice_Oneri + indice_Onorario + indice_Procedura + indice_Articolo + indice_Data_Ins + indice_Aggiornam + indice_Data_aggiudica + indice_Zone + indice_Cat + indice_Aggiudicatario
                    If indice_Aggiudicatario > maxu Then
                        maxu = indice_Aggiudicatario
                        Cells(1, u).EntireColumn.Insert xlShiftToRight
                        Cells(1, u) = "Aggiudicatario" & indice_Aggiudicatario
                    End If
                    Cells(ri, u) = Cells(i, "B")
                End Select
            End If
            i = j
         Next   'riparte il ciclo for fino a che non trova Rif_RiGa
        
        MsgBox "Done."
    End Sub
    



  • di Vecchio Frac data: 04/07/2017 15:43:43

    Per allegare un file c'è il pulsante apposito in cima e in calce alla discussione; tolgo la spunta su "Risolto" visto che risolto non è ^_^





  • di Vecchio Frac data: 04/07/2017 15:44:08

    edit: tolgo "Risolto"





  • di MarcoSpa data: 04/07/2017 15:50:45

    Hai ragione, cercavo il tasto mentre compilavo la risposta e non mi ero accorto che era nella pagina principale della discussione.



  • di Vecchio Frac data: 05/07/2017 09:25:19

    Dai commenti che hai fatto al codice vedo che non era molto chiaro... e non poteva che essere così, scusa ^_^
    Ora cerco di scrivere un post per fare chiarezza.





  • di MarcoSpa data: 05/07/2017 10:04:18

    No scusa, sono io che sono ignorante.. :-D



  • di Vecchio Frac data: 05/07/2017 10:08:32

    La situazione reale è più complessa di quella dell'esempio ^_^

    Nella parte di dichiarazione delle variabili, quelle elencate sono tutte variabili che servono al contesto. Il prefisso "max" non ha nessuna funzione particolare, avevo creato queste variabili di appoggio nell'esempio precedente solo per tenere conto del massimo indice raggiunto da una voce variabile (le voci variabili erano tre: colore, indirizzo e dati).

    L'istruzione
    ur = Range("A1").CurrentRegion.Rows.Count
    calcola il numero di righe presenti in tabella. La tabella è individuata a partire dalla cella A1. Il comando conta le righe della "regione corrente" intendendosi per tale quella zona di celle contigue non separate da righe o colonne vuote. In altre parole si individua un range di celle finchè non c'è almeno una riga vuota e almeno una colonna vuota. Il numero di righe della tabella è inserito nella variabile "ur", che serve dopo a scandire l'intero range di dati.

    In E1 e F1 sistemiamo le etichette dei campi "fissi".
    E' importante stabilire che ci sia almeno un campo fisso perchè è il discriminante dell'inizio della sequenza di campi da esaminare (per stabilire quanti e quali sono i doppioni).

    Poi col ciclo "For i = 1 to ur" parte la scansione della tabella dati, il contatore "i" individua la riga della tabella perciò l'istruzione successiva verifica che se nella cella alla "riga i, colonna A" c'è l'etichetta del campo principale (quello che stabilisce l'inizio di un gruppo intero, per capirci), assume alcune inizative perchè sa che sta iniziando un gruppo.

    La variabile j assicura l'allineamento della lettura del campo dopo aver inserito i doppioni incontrati lungo la lettura (è un po' nua furbata perchè modifica in corsa il contatore principale "i" e non si dovrebbe fare ^_^)

    La variabile ri invece si occupa di aggiornare il contatore delle righe in cui inserire i dati (nel tuo commento leggo "le celle ri-esime... non è proprio così che va letto: la cella in riga ri, colonna E assume il valore della cella in riga i, colonna B).

    L'Else non "divide i casi che ..." ma semplicemente analizza i campi diversi da quello fisso prncipale di cui all'If precedente. Nel ramo Else siamo pronti a gestire i casi in cui possono esserci dei campi doppi, per i quali serve aggiornare il relativo indice e aggiungere una colonna in più per ospitare il dato. Nel ramo Else quindi possiamo gestire i campi doppi fino al prossimo campo fisso, e il blocco Select Case assicura una gestione differenziata per ogni campo che può essere doppiato.

    In ognuno dei blocchi Select Case avviene la gestione dei casi doppi. Le variabili max* tengono conto del numero massimo di indice finora raggiunto per quel campo. Ogni volta che incontri un campo simile viene incrementato il relativo contatore indice_* (che identifica la colonna in cui fissare l'etichetta del nuovo campo). Se il valore indice attuale supera quello massimo già raggiunto in precedenza si genera un nuovo campo altrimenti i dati vengono posizionati in corrispondenza dei campi indice esistenti.
    (Se scorri con F8 passo passo la macro mentre viene eseguita, i passaggi risultano più chiari).

    Il caso reale è complicato solo dal fatto che ci sono molti più campi in gioco, ma la filosofia rimane ^_^
    Adesso devo fare delle telefonate, poi vedo se riesco a sistemarti il codice.





  • di MarcoSpa data: 05/07/2017 11:02:02

    Grazie sei molto gentile,
    Il codice che ho modificato per quello che ho capito non mi sembra avere dei problemi anche se andando avanti con F8 vedo che non tiene conto dei max* del ciclo for precedente quando riparte, forse max* si azzera?
    Ho notato che ho inizializzato "maxs" ma non l'ho usata, e cancellandola non è cambiato nulla.
    Si, la situazione reale è più complessa, ma come hai giustamente osservato si tratta solo di più campi.
    Faccio una domanda da principiante, ma non era meglio inizializzare le variabili di testo come string?

    Provo ancora a capire dove è il problema, e tu fai tutto quello che devi , se ci salto fuori posto.



  • di MarcoSpa data: 05/07/2017 11:16:14

    Ho avuto un intuizione di dove si inceppa..
    Per ogni nuovo ciclo in un caso come "Cdz_econom":
    u = 6 + indice_Ente_app + indice_Ogg + indice_Cdz_econom
    se u è il numero della colonna deve tenere conto dei max* dei casi precedenti, altrimenti considera solo gli indici che sono azzerati ad ogni ciclo.



  • di Vecchio Frac data: 05/07/2017 13:58:09

    cit. " ma non era meglio inizializzare le variabili di testo come string? "
    ---> Generalmente è così infatti. Ma noi qui maneggiamo solo indici numerici, non variabili di tipo stringa.

    cit. "se u è il numero della colonna deve tenere conto dei max* dei casi precedenti, altrimenti considera solo gli indici che sono azzerati ad ogni ciclo."
    ---> Sì è così







  • di Vecchio Frac data: 05/07/2017 16:14:54

    Ma sei sicuro che ti serve davvero trasformare in quel modo i dati? Di solito si normalizzano i campi riducendoli a uno e si moltiplicano le righe, per cui avresti un db finale con un'intestazione dove i campi compaiono una volta sola e dove si hanno molte righe (record) per ogni inserimento.
    
    
    Rif_RiGa Rif_Gara Ente_app Cat Aggiudicatario
    794642 11376971 Unione Dei Comuni Bassa Reggiana Di Novellara T-AF 315572 - VINCITORE NON
    794642 11376971 Piazzale Marconi N. 1 M-OG1 - Vincitore:
    794642 11376971 42017 Novellara (re) M-OG2







  • di MarcoSpa data: 05/07/2017 16:34:04

    Mi piacerebbe, solo che alcuni campi contengono molte info diverse, per esempio "cat", anzi forse è solo per quello che lo faccio, perchè mi interessa filtrare le diverse cat: T-AF; M-OG1; M-OG2; M-OG3; M-OG4; ecc.
    Il primo caso è il più emblematico perché ha tutte le categorie, ma non è l'unico con più di una categoria.
    Comunque mi accontenterei volentieri di un file con i campi normalizzati, che se ho capito bene significa che in una cella sono contenute tutte le info del campo
    Il file grezzo deriva da un copia e incolla di una sesantina di tabelle in WORD.





  • di Vecchio Frac data: 05/07/2017 16:51:47

    Non mi sono spiegato bene... di solito le tabelle hanno un solo campo univoco (di intestazione) e molti record (righe). Così poi fare interrogazioni e filtri è più facile.
    Nel tuo caso, fermiamoci al primo set di righe, tu hai tre righe di dati per "Ente_app".
    Invece di impostare un database prevedendo tre campi diversi "ente_app1", "ente_app2" e "ente_app3", è quasi sempre necessario normalizzare il db facendo figurare un solo campo univoco "ente_app" e tre righe di dati ad esso correlate.

    cit. "se ho capito bene significa che in una cella sono contenute tutte le info del campo "
    ---> No, significa ridurre alla regola normale che vuole che ci siano campi univoci per accogliere il dato di quella categoria. Infatti non è rilevante il numero di righe (set di record o recordset) ma la struttura del db (cioè quanti campi e di che tipo). Non avrai quindi in una cella tutte le informazioni del campo, ma una sola informazione per ogni campo spalmata su più righe (vedi l'esempio del mio post precedente: i codici Rif_RiGa e Rif_Gara sono scritti tante volte quanti sono i contenuti diversi dei campi successivi). Per cui invece di avere ad esempio Cat_1 fino a Cat_11 avrai un solo campo cat (sul quale fare le interrogazioni) e undici righe diverse (con diverse informazioni "Cat") che si riferiscono allo stesso codice gara.

    Se come credo è necessario compiere questa operazione, bisognerà ristudiare il codice e quindi temo che dovrai avere ancora un po' di pazienza e darmi fiducia ^_^

    cit. "deriva da un copia e incolla di una sessantina di tabelle in WORD"
    ---> Si potrebbe addirittura leggere il dato direttamente dal file di Word evitando i problemi tipici del copia incolla. Ma in questa fase non complicherei le informazioni che ti sto dando.





  • di MarcoSpa data: 05/07/2017 16:56:05

    Scusa non avevo visto bene!!
    cit:
    Rif_RiGa Rif_Gara Ente_app Cat Aggiudicatario

    794642 11376971 Unione Dei Comuni Bassa Reggiana Di Novellara T-AF 315572 - VINCITORE NON

    794642 11376971 Piazzale Marconi N. 1 M-OG1 - Vincitore:

    794642 11376971 42017 Novellara (re) M-OG2

    Così può andare, perché sono ripetuti i "Rif_RiGa" e "Rif_Gara" in tutti i Campi diversi!!



  • di MarcoSpa data: 05/07/2017 16:58:54

    hai risp mentre rip anche io.. si, OK, TUTTO CORRETTO,
    cit:
    ...Infatti non è rilevante il numero di righe (set di record o recordset) ma la struttura del db (cioè quanti campi e di che tipo). Non avrai quindi in una cella tutte le informazioni del campo, ma una sola informazione per ogni campo spalmata su più righe (vedi l'esempio del mio post precedente: i codici Rif_RiGa e Rif_Gara sono scritti tante volte quanti sono i contenuti diversi dei campi successivi). Per cui invece di avere ad esempio Cat_1 fino a Cat_11 avrai un solo campo cat (sul quale fare le interrogazioni) e undici righe diverse (con diverse informazioni "Cat") che si riferiscono allo stesso codice gara.

    Esatto!



  • di MarcoSpa data: 05/07/2017 17:02:19

    cit: Si potrebbe addirittura leggere il dato direttamente dal file di Word evitando i problemi tipici del copia incolla. Ma in questa fase non complicherei le informazioni che ti sto dando.

    Grazie..



  • di Vecchio Frac data: 06/07/2017 10:33:05

    Dopo diverse difficoltà, e non nascondo che la cosa mi ha tenuto impegnato un bel po', ti propongo il codice seguente (ho cercato anche di commentarlo per spiegare i passi principali).
    Il risultato è soddisfacente e spero che possa andare bene (perlomeno sei in grado di fare i filtri sui singoli campi).
    Il problema è che non ci possono essere correlazioni tra campi diversi che dovrebbero appartenere a tabelle diverse (per esempio quando arrivi al dato "Ogg" = "M-OG3", quale dovrebeb essere l'"Ente_app" visto che le tre righe prima hanno tre diversi valori)?
    Comunque fai girare sulla base dati reale e vedi cosa succede.

     
    Option Explicit
    
    Sub transform_VF2()
    Dim dict() As Object
    Dim headers As Object
    Dim c As Range
    Dim s As String, p As String
    Dim i As Long
    Dim co As Long, ur As Long
    Dim ri As Long, idx As Long
    Dim rr As Long, last_row As Long, j As Long
    Dim v As Variant, vv As Variant, o As Variant
    
        'selezione foglio e pulizia
        Sheets("db").Select
        Range("E1:EW5000").ClearContents
        
        'calcolo ultima riga del database
        ur = Range("A1").CurrentRegion.Rows.Count
        
        'inserisco gli headers dei campi a partire da colonna E
        'in un oggetto dizionario
        Set headers = CreateObject("Scripting.Dictionary")
        co = 5
        For ri = 1 To ur
            s = Cells(ri, "A")
            If Not headers.exists(s) Then
                headers(s) = s
                Cells(1, co) = s
                co = co + 1
            End If
        Next
    
        'per memorizzare i dati utilizzo un oggetto "dizionario" ("dict")
        'in cui possono essere inseriti dati associati a una chiave
        'il dizionario ha forma diz = chiave, valore e i suoi dati
        'vengono inseriti con l'istruzione dizionario(chiave)=valore
        'il valore può essere costituito da qualunque oggetto, anche un
        'array di dati, basta ricordarsi come è costruito :)
        'in particolare creo una matrice di dizionari indicizzati da 1 in poi
        'col discriminante costiuito da Rif_RiGa
        
        'per ogni zona del database intervallata dal codice univoco Rif_RiGa,
        'creo una voce del dizionario dict() dove memorizzo il valore del
        'codice di riferimento (in Rif_RiGa) e il valore della voce singola
        'per esempio la prima zona di dati (A1:B30) è chiamata dict(1)
        'e ha chiavi corrispondenti ai campi della colonna A, e valori
        'corrispondenti ai valori della singola riga; in caso di valori multipli
        'questi sono memorizzati nella corrispondente chiave come singolo dato
        'separato dal carattere speciale "|"; così alla fine abbiamo:
        'dict(1)("Rif_RiGa") = 794642, 794642
        'dict(1)("Rif_Gara") = 794642, 11376971
        'dict(1)("Ente_app") = 794642, Unione dei Comuni|Piazzale Marconi|42017 Novellara
        For i = 1 To ur
            s = Cells(i, "A")
            
            If s = "Rif_RiGa" Then
                idx = idx + 1
                ReDim Preserve dict(idx) As Object
                
                Set dict(idx) = CreateObject("Scripting.Dictionary")
                dict(idx)(s) = Array(Cells(i, "B"), Cells(i, "B"))
            Else
                If Not dict(idx).exists(s) Then
                    dict(idx)(s) = Array(dict(idx)("Rif_RiGa")(0), Cells(i, "B"))
                Else
                    p = dict(idx)(s)(1) & "|" & Cells(i, "B")
                    If Left(p, 1) = "|" Then p = Mid(p, 2)
                    dict(idx)(s) = Array(dict(idx)("Rif_RiGa")(0), p)
                End If
            End If
        Next
        
        'ora che abbiamo riempito il dizionario di dati e valori possiamo
        'recuperarli, scorrendo l'array di dizionari, e sistemandoli nelle corrette
        'righe, colonne (a partire da E2)
        'In caso di valori multipli per un campo, occorre ricordare l'indice di riga
        'dell'ultimo valore posizionato epr poter ricominciare a piazzare il dato
        'successivo nella giusta posizione di riga
        'Per ogni riga è riportato, in colonna E, il codice chiave base (quello del
        'campo Rif_RiGa relativo alla porzione del dizionario in esame)
        ri = 2
        For i = 1 To idx
            For Each v In dict(i)       'etichetta header
                s = dict(i)(v)(0)       'dict()=array(codice rif_RiGa, value)
                Set c = Range("1:1").Find(v, lookat:=xlWhole)
                p = dict(i)(v)(1)       'value
                If InStr(p, "|") = 0 Then
                    Cells(ri, c.Column) = p
                Else
                    rr = ri
                    For Each vv In Split(p, "|")
                        Cells(rr, c.Column) = vv
                        Cells(rr, "E") = dict(i)("Rif_RiGa")(1)
                        rr = rr + 1
                    Next
                End If
                If rr > last_row Then last_row = rr
            Next
            ri = last_row
        Next
        
        MsgBox "Finito!", vbInformation
    End Sub
    






  • di MarcoSpa data: 07/07/2017 09:16:28

    Grazie, ieri ero fuori ufficio, ma adesso mi applico subito.
    Ti sono molto grato.



  • di MarcoSpa data: 07/07/2017 11:08:33

    Mi sembra di capire che l'oggetto "dict" sia come un recipiene dove i dati letti dalla colonna A vengono associati ad una chiave univoca rappresentata da "Rif_RiGa" e ordinati.
    Poi hai costruito un array con tutti i dict, e alla fine si è potuto estrarre i dati che erano separati da "|".
    Hai creato una struttura intermedia invisibile più efficente per poter pescare e posizionare i dati in modo ordinato, legati alla chiave.

    Molti righe rimangono per me oscure non te lo nascondo, ma con questa struttura di output posso fare una tabella e interrogarla con agilità.

    Grazie ancora, invidio la tua dimestichezza con il codice.

    RISOLTO!



  • di Vecchio Frac data: 07/07/2017 13:59:23

    Sull'uso dell'oggetto dictionary, è come dici.
    Se hai interesse o curiosità di approfondire alcune parti o alcune tecniche, non esitare ad aprire una nuova discussione e chiedere spiegazioni.
    Alla fine il codice che ne è venuto fuori non è eccessivamente complesso: la parte difficile è stata capire come affrontare il problema e descriverlo nei passi da compiere (è quello che dico sempre a tutti: descrivere il problema e la sua soluzione, poi stendere il codice).
    Non invidiarmi perchè non ne vale la pena :)
    Alla prossima.