Aggiornamento tabella attraverso VBA - errore memoria

di Anonimizzato20710 il
13 risposte
Ciao a tutti,
Ho la necessità di aggiornare un campo(stringa) di una tabella attraverso VBA. La tabella deve essere letta record per record andando ad aggiornare il campo con una stringa ottenuta da un'altra tabella in base a determinate condizioni(per questo utilizzo uno script piuttosto che una semplice query di update).
Dopo l'esecuzione dello script, il database cresce di dimensioni notevolmente e andando ad analizzare la tabella modificata(ad esempio con una query) compaiono errori di memoria("memoria insufficiente"). Provando ad esportare in Excel la tabella modificata, ottengo lo stesso errore.
La tabella ha circa 150000 record.

Riporto un esempio del codice VBA che utilizzo, tralasciando la logica con cui ottengo la stringa da scrivere:

Public Sub Prova()

Dim DBCorrente As Dao.Database
Dim Tabella As Dao.Recordset
Dim i As Long
Dim s As String
Set DBCorrente = CurrentDb
Set Tabella = DBCorrente.OpenRecordset("SKU", dbOpenDynaset)
i = 1
Tabella.MoveNext
Do Until Tabella.EOF
Tabella.Edit
Tabella.Fields("IDTRENO") = "COD_" & i & "_END" 'La stringa da inserire ha questo formato
Tabella.Update
i = i + 1
Tabella.MoveNext
Loop
Tabella.Close
DBCorrente.Close
End Sub


Ho il sospetto che la mia procedura allochi delle risorse che non vengono rilasciate. Suggerimenti?

Grazie.

13 Risposte

  • È una operazione che devi fare una volta sola perchè ti sei accorto di un baco progettuale? Oppure vuoi una cosa sistematica?
    Nella prima ipotesi, io spesso provo a cavarmela con più passaggi "spartani" a mano.
    Nella seconda ipotesi...sospetto qualche errore di progettazione database.
  • La procedura vba che esponi non mostra errori strutturali... puoi forzare la distruzione delle 2 variabili oggetto alla fine ... settando a Nothing.... ma poca roba che non giustifica.
    Non capisco il primo MoveNext prima del ciclo... sicuro non sia un MoveFirst..?

    In ogni modo essendo 150000 Records potresti valutare di inserire il processo in una transazione...migliorerebbe le prestazioni...

    Purtroppo per l'errore che ricevi escludo dipenda dal codice... ti suggerirei di provare a creare un Db vuoto ed importi tutto dal vecchio compattando e compilando il codice in quanto sospetto possa essere un principio di corruzione del db.
  • Grazie per le risposte immediate.
    Il database è molto semplice, creato da poco. Escludo l'errore progettuale, forse si sarà corrotto.

    Per conoscenza personale, qual'e la differenza(tecnica) tra fare questo aggiornamento tramite transazione o tramite script? Perché è più efficiente?

    Vi presento il mio caso(è un esempio):

    - Ipotizziamo di avere una tabella con gli orari dei treni:
    COD DA A COD2
    ------------------------
    A 09:00 10:00 xxx
    A 10:00 12:00 yyy
    ..
    B 08:00 10:00 kkk
    B 10:00 13:00 zzz
    ..

    - L'altra tabella(quella che nel mio caso ha 150K record) è invece fatta cosi:
    COD H
    ----------------------
    A 08:30
    A 09:45
    ..
    B 13:40
    ..

    Il mio obiettivo è quello di individuare per la secondo tabella in quale fascia oraria rientra il treno con la codifica(COD) e quindi individuare COD2.
    Secondo voi è fattibile con una transazione(in Access)?

    Grazie.
  • fmara ha scritto:


    ...
    Per conoscenza personale, qual'e la differenza(tecnica) tra fare questo aggiornamento tramite transazione o tramite script? Perché è più efficiente?
    ...
    Che cosa intendi per script? La domanda è dovuta al fatto che lo contrapponi alla transazione quindi sembra che per te siano due vie alternative.
    Per capirci: il codice che hai indicato nel primo post è normale codice vba e può inserito in una transazione (anzi, citando Gibra: "qualsiasi azione CRUD deve, e ribadisco deve, essere eseguita all'interno di una transaction")
    (a solo titolo d'esempio)
  • Grazie per la risposta.
    Non avevo ben chiaro il concetto di transazione(o meglio, nel caso sopra, intendevo porre la logica di ricerca all'interno di una query di aggiornamento, che poi posso committare o meno). Dopo aver letto l'articolo allegato, in termini di consistenza è di certo migliore l'uso di una transazione, ma non capisco perché sia migliore in termini di efficienza delle prestazioni.

    Tornando al mio esempio, e qui pongo la domanda in modo diverso, il mio esempio sopra è fattibile con una query di update?
  • fmara ha scritto:


    ...non capisco perché sia migliore in termini di efficienza delle prestazioni...
    In parole super povere che ho letto da qualche parte, oltre ai benefici in termini di sicurezza per l'integrità dei dati, la transazione accede al disco per salvare i dati una volta sola, non dopo ogni record.
  • In sostanza salva sempre e non solo una volta... ma in memoria o meglio in quell'area che il begin si riserva... non fisicamente sull'origine spostando poi la copia in blocco alla fine... in questo modo le continue richieste di accesso ed Update vengono riservate ad un'area di memoria temporanea che può risultare più performante...

    Tuttavia l'oggetto del problema mi risulta estremamente poco chiaro.
  • Grazie per la spiegazione.
    Cosa non ti è chiaro? Il mio problema di esempio?

    Quando ho aperto questo thread, pensavo di aver sbagliato qualcosa nello script per i problemi di prestazione che ottenevo(il primo post).
    Ora che mi avete chiarito li idee(e vi ringrazio ancora una volta), vi chiedevo, se ci fosse qualche maniera più efficiente per risolvere il mio problema(di cui ho riportato un esempio sul secondo post, è poco chiaro?).
    Non che mi serva, ma è una questione di curiosità personale. Se avete qualche idea, sono lieto di ascoltarla.
    Grazie ancora.
  • fmara ha scritto:


    ...vi chiedevo, se ci fosse qualche maniera più efficiente per risolvere il mio problema(di cui ho riportato un esempio sul secondo post, è poco chiaro?).
    Stavo proprio rileggendo l'intero thread ed ho visto nel frattempo questo intervento che è servito a confermare... il dubbio.
    Quello che non ci è chiaro (credo che anche @Alex si trovi in questa situazione) è come ricondurre il tuo primo post con l'esempio che hai fatto. Sembrano applicarsi a due situazioni completamente diverse.
    Non potresti mai fare una query di update per ottenere la stessa cosa che fa il codice del primo post.
    Poi nell'esempio si parla di trovare COD2 in base all'orario e quello non lo ottenevi comunque con quel codice iniziale. Quello sì, si può fare con una query di update.
    Cosa è meglio? dipende dalla situazione, perché sono due situazioni diverse.
    Preciso comunque che anche la query di update può essere fatta da codice ed inserita in una transazione.
  • Il mio esempio iniziale è privo della logica di ricerca nella seconda tabella. In sostanza, al posto di:

    Tabella.Fields("IDTRENO") = "COD_" & i & "_END" 'La stringa da inserire ha questo formato

    Avevo fatto una "Find" su un'altra tabella ed ottenevo quello che nell'altro post ho chiamato COD2.

    All'inizio temevo fosse solo un problema di scrittura sulla tabella, per cui non ho riportato l'esempio completo.

    Al di la del codice iniziale, pensi che si possa fare una query di update per risolvere il mio secondo esempio(il caso degli orari)?
  • fmara ha scritto:


    Il mio esempio iniziale è privo della logica di ricerca nella seconda tabella...
    Non era un dettaglio trascurabile.

    fmara ha scritto:


    ... pensi che si possa fare una query di update per risolvere il mio secondo esempio(il caso degli orari)?
    Sì.
    Parti dall'ottenere una query di selezione che per ogni record della seconda tabella trovi il corrispondente COD2 della prima. Solo dopo si passa all'update. Una query di selezione è abbastanza semplice, devi farcela da solo, o almeno scrivere fino a dove arrivi e che cosa non ti soddisfa.
  • Effettivamente la soluzione è più facile del previsto.
    Ho provato a fare la query in due modi.
    1)
    UPDATE TAB2 T2
    SET T2.COD2 = (SELECT T1.COD2 FROM TAB1 T1 WHERE T1.COD=T2.COD AND T1.DA<=T2.H AND T2.H<T1.A);
    Access mi da un errore "Operation must use an updateable query".
    2)
    UPDATE TAB2 T2 INNER JOIN TAB1 T1 ON T1.COD = T2.COD SET T2.COD2 = T1.COD2
    WHERE (T1.DA<=T2.H AND T2.H<T1.A);
    E' OK.

    Che differenza c'è tra le due?
Devi accedere o registrarti per scrivere nel forum
13 risposte