Ciclo per duplicare record

di il
13 risposte

Ciclo per duplicare record

Buongiorno
dopo un bel po' di tempo torno ad avere bisogno del vostro aiuto.
Ho la seguente tabella:
Tb612_DatiTecnici
con i seguenti campi (solo alcuni per es. in realtà sono una cinquantina):
ID_DatiTecnici (chiave primaria)
ID_Modello (lato molti di un relazione uno_a_molti con la tabella Modelli)
GruppoLega
LegaVendita
LegaProduzione
ecc...

In una parte precedente del codice ho duplicato un record della tabella Modelli e ho memorizzato nelle variabili
ModOrig = ID_Modello del record originale
ModDupl = ID_Modello del record duplicato

Ora devo cercare in Tb612_DatiTecnici il record (univoco) dove ID_Modello=ModOrig e duplicarlo copiando in modo identico tutti i campi tranne la chiave primaria ID_Dati tecnici e l'ID_Modello che dovrà essere = ModDupl.

Ho cercato in vecchi post se c'era una procedura con un ciclo per copiare tutti i campi poiché sono molti (è dovrò replicare anche in altre tabelle) e volevo velocizzare rispetto all'utilizzo di INSERT INTO... ho trovato un codice proposto in un post che ho provato a sistemare perché nell'originale occorreva non copiare solo la chiave primaria e c'era un IF, avendo due campi da "saltare" ho provato a cambiare inserendo un select... ma quando arriva al case else (in pratica al terzo campo del record) mi restituisce questo errore "Errore di runtime 3265, elemento non trovato in questa raccolta" eppure il fld.name corrisponde alla terza colonna e il fld.value è corretto.
Non capisco l'errore...
Grazie mille

    Dim rsSource    As DAO.Recordset
    Dim fld         As DAO.Field
    Set rsSource = DBEngine(0)(0).OpenRecordset("SELECT * FROM Tb612_DatiTEcnici WHERE ID_Modello = " & IDModOrig, dbOpenSnapshot, dbReadOnly)

        Me.RecordsetClone.AddNew
        For Each fld In rsSource.Fields
            Select Case fld.Name
                Case "ID_DatiTecnici"

                Case "ID_Modello"
                    Me.RecordsetClone.Fields(fld.Name) = IDModDupl
                Case Else
                    Me.RecordsetClone.Fields(fld.Name) = fld.Value
            End Select
        Next
        Me.RecordsetClone.Update

13 Risposte

  • Re: Ciclo per duplicare record

    Se il Recordset ha come origine una Query che usa ALIAS penso si debba sostituire il fld.Name con SourceField.
    Nel tuo caso usi [*] quindi non si comprende...

    Metti un DEBUG.PRINT e verifica le 2 properties, probabilmente la proprietà NAME restituisce l'ALIAS che non corrisponde al nome del campo della Maschera.
  • Re: Ciclo per duplicare record

    L'origine del Recordset è una tabella. Non è una query
  • Re: Ciclo per duplicare record

    Allora il Campo che cerchi, come dice lui, non c'è...
    Fai DEBUG e stampa il nome in finestra immediata, magari ha ragione, verifica bene tutto deve essere una cosa banale.
  • Re: Ciclo per duplicare record

    Non capisco proprio, in Immediata il come del campo è giusto... anche perché, come potrebbe essere sbagliato visto che la tabella di origine e quella di arrivo sono la stessa? Cioè, copia il campo dalla tabella di origine e poi aggiunge un record alla stessa tabella perciò non può "sbagliare nome"... o no?
    Anche io ero convinta fosse un errore banale, ma non capisco cosa...
  • Re: Ciclo per duplicare record

    Crodino ha scritto:


    Anche io ero convinta fosse un errore banale, ma non capisco cosa...
    Siccome il messaggio è chiaro (Campo Non trovato) occorre fare debug ma molto probabilmente il recordsetclone che utilizzi non è collegato alla tabella a cui tu pensi sia collegato (oppure potresti avere dei caratteri strani nel nome campo magari degli spazi e/o caratteri che sarebbe meglio evitare tipo ° § # + * lettere accentate e chissà quanti altri) ...
  • Re: Ciclo per duplicare record

    Domani riprovo con calma... c'è un modo per verificare il valore del recordsetclone così controllo anche quello..? Perché è evidente che se non è zuppa è pan bagnato!!!
  • Re: Ciclo per duplicare record

    RISOLTO!!
    il problema effettivamente era il Recordset a cui puntava che era sbagliato!
    Che errore cretino, non avevo calcolato che partivo da una maschera (collegata ad altra tabella) per duplicare e poi cercavo di duplicare altre tabelle (collegate non a quella maschera) e ovviamente andava in errore.
    Ho risolto così:
    Dim rsSource    As DAO.Recordset
            Dim rsDest      As DAO.Recordset
            Dim fld         As DAO.Field
            Set rsSource = DBEngine(0)(0).OpenRecordset("SELECT * FROM Tb612_DatiTecnici WHERE ID_Modello = " & IDModOrig, dbOpenSnapshot, dbReadOnly)
                If Not (rsSource.EOF And rsSource.BOF) Then
                    Set rsDest = DBEngine(0)(0).OpenRecordset("Tb612_DatiTecnici")
                End If
                rsDest.AddNew
                For Each fld In rsSource.Fields
                    Select Case fld.Name
                        Case "ID_DatiTecnici"
                        Case "ID_Modello"
                            rsDest.Fields(fld.Name) = IDModDupl
                        Case Else
                            rsDest.Fields(fld.Name) = fld.Value
                    End Select
                Next
                rsDest.Update
                rsDest.Close
                rsSource.Close
    
    Funziona ma se individuate qualche errore sono qui per imparare..
    grazie mille
  • Re: Ciclo per duplicare record

    Crodino ha scritto:


    Funziona ma se individuate qualche errore sono qui per imparare..
    
    Dim rsSource    As DAO.Recordset
    Dim rsDest      As DAO.Recordset
    Dim fld         As DAO.Field
            Set rsSource = DBEngine(0)(0).OpenRecordset("SELECT * FROM Tb612_DatiTecnici WHERE ID_Modello = " & IDModOrig, dbOpenSnapshot, dbReadOnly)
            If Not (rsSource.EOF And rsSource.BOF) Then
                Set rsDest = DBEngine(0)(0).OpenRecordset("Tb612_DatiTecnici", suggerimento : esplicita come vuoi aprire il recordset)
                rsDest.AddNew
                For Each fld In rsSource.Fields
                    Select Case fld.Name
                        Case "ID_DatiTecnici"
                        Case "ID_Modello"
                            rsDest.Fields(fld.Name) = IDModDupl
                        Case Else
                            rsDest.Fields(fld.Name) = fld.Value
                    End Select
                Next
                rsDest.Update
                rsDest.Close
                set rsDest = nothing
            End If      
            rsSource.Close
            set rsSource = nothing
    
    Una corretta indentazione del codice (purtroppo l'editor del forum non aiuta) permette di leggere meglio il codice e a trovare gli errori.
    Esplicitare i parametri facoltativi (vedi openrecordset) aiuta ad imporre l'uso dei parametri che effettivamente vuoi (e non quelli che credi di volere).
    Gli oggetti si distruggono (vedi i vari set obj = nothing)
    Confesso che io testo solo per EOF e non mi curo del BOF però non sono convinto/sicuro che EOF/BOF siano entrambi veri contemporaneamente. Nel caso non lo fossero devi scrivere "If Not (rsSource.EOF OR rsSource.BOF) Then" ...
    Se non crei rsDest NON puoi certo fare l'addnew (vedi lo spostamento dell' End If)
    Nel codice manca la gestione degli errori (operazione da implementare a tua cura)
  • Re: Ciclo per duplicare record

    max.riservo ha scritto:


    Confesso che io testo solo per EOF e non mi curo del BOF però non sono convinto/sicuro che EOF/BOF siano entrambi veri contemporaneamente. Nel caso non lo fossero devi scrivere "If Not (rsSource.EOF OR rsSource.BOF) Then" ...
    Una semplice ricerca mi costringe a correggere quanto sopra : pare che BOF e EOF possano essere veri in contemporanea.
    Alcuni modi per scorrere un recordset e/o verificare se un recordset è vuoto :
    
    'Scorrere dal primo all'ultimo (solo se ci sono records)
    Set rst = dbs.OpenRecordset("SELECT * FROM Table1", dbOpenDynaset)
    Do While Not rst.EOF
        rst.MoveNext
    Loop
    
    
    'Scorrere dal primo all'ultimo (solo se ci sono records)
    Set rst = dbs.OpenRecordset("SELECT * FROM Table1", dbOpenDynaset)
    Do Until rst.EOF
        rst.MoveNext
    Loop
    
    
    'Scorrere dall'ultimo al primo  (solo se ci sono records)
    Set rst = dbs.OpenRecordset("SELECT * FROM Table1", dbOpenDynaset)
    rst.MoveLast
    
    Do While Not rst.BOF
        rst.MovePrevious
    Loop
    
    
    'Verificare che il recordset abbia dei records
    Set rst = dbs.OpenRecordset("SELECT * FROM Table1", dbOpenDynaset)
    If Not (rst.BOF And rst.EOF) Then
    End If
    
  • Re: Ciclo per duplicare record

    Ottimo, grazie
  • Re: Ciclo per duplicare record

    max.riservo ha scritto:


    Confesso che io testo solo per EOF e non mi curo del BOF però non sono convinto/sicuro che EOF/BOF siano entrambi veri contemporaneamente. Nel caso non lo fossero devi scrivere "If Not (rsSource.EOF OR rsSource.BOF) Then" ...
    Una semplice ricerca mi costringe a correggere quanto sopra : pare che BOF e EOF possano essere veri in contemporanea.
    [/quote]

    Ciao MAX, confermo, aggiungo 2 considerazioni:
    1) BOF ed EOF sono veri entrambi quando il RS è vuoto
    2) Per ciclare si testa solo EOF

    Come te io controllavo solo EOF, ma non ricordo con che combinazione ho avuto seri problemi, da allora sempre AND dei 2:
    
    IF (rs.BOF AND rs.Eof) Then
       ' Recordset Vuoto
    Else
       ' Recordset NON vuoto
    End If
    La questione dello scorrere con MoveLast il rs non serve a NULLA, se non ad aggiornare la proprietà RecordCount quando il RS non è aperto in modalità acOpenTable, in questo caso, e solo se ha senso sapere in anticipo quanti sono, ad esempio per muovere una Progress, allora prima di iniziare il Ciclo si aggiorna il BOOKMARK sul LAST obbligando a rileggere ed aggiornare Recordcount.
  • Re: Ciclo per duplicare record

    @Alex ha scritto:


    Ciao MAX, confermo, aggiungo 2 considerazioni:
    1) BOF ed EOF sono veri entrambi quando il RS è vuoto
    2) Per ciclare si testa solo EOF

    Come te io controllavo solo EOF, ma non ricordo con che combinazione ho avuto seri problemi, da allora sempre AND dei 2:
    
    IF (rs.BOF AND rs.Eof) Then
       ' Recordset Vuoto
    Else
       ' Recordset NON vuoto
    End If
    Ciao Alex,
    se e quando trovi la motivazione per testarli entrambi dimmelo che cambio abitudine. Per ora rimango sul EOF.

    @Alex ha scritto:


    La questione dello scorrere con MoveLast il rs non serve a NULLA, se non ad aggiornare la proprietà RecordCount quando il RS non è aperto in modalità acOpenTable, in questo caso, e solo se ha senso sapere in anticipo quanti sono, ad esempio per muovere una Progress, allora prima di iniziare il Ciclo si aggiorna il BOOKMARK sul LAST obbligando a rileggere ed aggiornare Recordcount.
    Concordo, io ho suggerito il MoveLast in abbinamento al MovePrevious nel caso si volesse scorrere il recordset partendo dalla fine (personalmente non l'ho mai usato, nel caso avrei ordinato il recodset utilizzando Order BY field DESC scorrendo il recordset dall'inizio alla fine).
  • Re: Ciclo per duplicare record

    max.riservo ha scritto:


    @Alex ha scritto:


    Ciao MAX, confermo, aggiungo 2 considerazioni:
    1) BOF ed EOF sono veri entrambi quando il RS è vuoto
    2) Per ciclare si testa solo EOF

    Come te io controllavo solo EOF, ma non ricordo con che combinazione ho avuto seri problemi, da allora sempre AND dei 2:
    
    IF (rs.BOF AND rs.Eof) Then
       ' Recordset Vuoto
    Else
       ' Recordset NON vuoto
    End If
    Ciao Alex,
    se e quando trovi la motivazione per testarli entrambi dimmelo che cambio abitudine. Per ora rimango sul EOF.
    Purtroppo non lo ricordo più, passato qualche lustro , ma sono certo di ricordare che mi ha fatto sudare parecchio, proprio perchè sono di quelle cose che dai per scontato e tralasci... poi non ricordo nemmeno se ho indagato a fondo per capire i motivi o se con l'AND dei 2 risolvendo poi non ho più nemmeno ripensato alla cosa...
Devi accedere o registrarti per scrivere nel forum
13 risposte