Errore 3146 - ODBC: chiamata non riuscita

di il
10 risposte

Errore 3146 - ODBC: chiamata non riuscita

Buonasera a tutti

Mi sta capitando su un FE di access che gira con il runtime e si connette via ODBC ad un server SQL di avere sporadicamente il seguente errore:

3146 - ODBC: chiamata non riuscita.

[microsoft][ODBC Driver 13 for SQL Server] Errore di
collegamento durante la comunicazione. (#0)

Il file di access è molto semplice con una sola maschera e alcune tabelle collegate via ODBC che alla pressione di un tasto scrive un record su una tabella posta sul server SQL.

l'errore si verifica su una banale dlookup che è all'inizio del processo di scrittura per recuperare un dato

            On Error GoTo errore
            VarStato = Nz(DLookup("Stato", "TabellaRisorseAssegnate", "IdRecord=" & Me.Controls("IdRisorseAssegnate" & Indice)), 99)
            On Error GoTo 0
Ho inserito il controllo errore per cui l'applicazione non si blocca provocando la chiusura di access e premendo ok al messaggio di errore e riprovando l'operazione va a buon fine.
Mi è successo però un paio di volte che non si riesca a ripristinare la connessione con SQL, a quel punto ho verificato la connessione di rete (sono su rete WIFI) e questa era attiva. Ho riavviato il PC e tutto è ripartito correttamente.

Da quello che capisco il problema è un problema di rete, come potrei fare a ripristinare il collegamento SQL senza riavviare il PC?
Premetto che non ho ancora avuto modo di provare se chiudere e riaprire access sia sufficiente a risolvere il problema nel caso potrei chiudere e riaprire l'applicazione.

10 Risposte

  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Io proverei ad eliminare l'utilizzo del DLookUp in favore della query equivalente : https://www.sqlservercentral.com/articles/converting-access-queries-with-iff-and-dlookup-to-sql-server
    Oppure potresti provare la funzione EDLookUP : https://accessexperts.com/blog/2020/07/23/alternative-solution-to-dcount-and-dlookup-with-sql-server-backend/
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Grazie per il consiglio

    Ho provato a rimuovere il dlookup ma non ho risolto il problema che si è ripresentato.

    Chiudere e riaprire access sembra risolvere il problema.

    Stavo pensando di disconnettere e riconnettere le tabelle collegate per ovviare alla problematica.

    Vi tengo aggiornati sull'evoluzione
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    La prima cosa da fare è aprire la Tabella e verificare che la connessione sia corretta.
    Da valutare che, se apporti modifiche al BE(Server) devi Ripristinare il Link delle Tabelle, momento in cui rilegge la struttura dati.
    Da valutare che, le Tabelle si dovrebbero Collegare all'apertura e scollegare alla chiusura, soprattutto per motivi di sicurezza... se io con un mio programmino di Access mi Linko alle tue LinkedTable posso tranquillamente cancellare tutto senza immettere User/Pwd in quanto salvate nella tua connessione, che peraltro è visibile in chiaro nella Tabella di sistema.

    Detto quanto sopra..., nel caso puoi mostrare meglio il codice di scrittura che usi...?
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Ciao Alex

    Il problema si verifica durante il funzionamento, oggi è andato tutto bene fino alle 15 poi si è presentato il problema, il BE non è cambiato e il problema non si verifica durante una scrittura ma durante una lettura.
    Il codice con cui ho sostituito la dlookup è il seguente:
    
                On Error GoTo errore
                Set db = CurrentDb()
                STRSQL = "SELECT TabellaRisorseAssegnate.Stato FROM TabellaRisorseAssegnate WHERE IdRecord=" & Me.Controls("IdRisorseAssegnate" & Indice) & ";"
                Set RstRisorse = db.OpenRecordset(STRSQL, dbOpenSnapshot)
                If RstRisorse.RecordCount > 0 Then
                    VarStato = Nz(RstRisorse!stato, 0)
                End If
                RstRisorse.Close
                db.Close
    
    dopo questa lettura c'è una scrittura
    
    
                        Set wrk = DBEngine(0)
                        Set db = CurrentDb()
                        On Error GoTo trans_Err
                        wrk.BeginTrans
    
                        STRSQL = "UPDATE TabellaPianificazioneReparto SET TabellaPianificazioneReparto.QtaProdotta =" & Me.Controls("RisorsaEff" & Indice) & " WHERE (((TabellaPianificazioneReparto.IdRecord)=" & Me.Controls("IdPianificazione" & Indice) & "));"
                        db.Execute STRSQL, dbSeeChanges
                        
                        STRSQL = "UPDATE TabellaRisorseAssegnate SET TabellaRisorseAssegnate.QtaProdotta =" & Me.Controls("RisorsaEff" & Indice) & " WHERE (((TabellaRisorseAssegnate.IdRecord)=" & Me.Controls("IdRisorseAssegnate" & Indice) & "));"
                        db.Execute STRSQL, dbSeeChanges
                        
                        STRSQL = "INSERT INTO TabellaPezziProdotti ( IdRisorsaAssegnata, Data, QtaProd, TempoImpiegato ) values ('" & Me.Controls("IdRisorseAssegnate" & Indice) & "',#" & Format(Now(), "mm/dd/yyyy hh:mm:ss") & "#, '1','" & TempoImpiegato & "');"
                        db.Execute STRSQL, dbSeeChanges
                        
                        wrk.CommitTrans dbForceOSFlush
                        db.Close
                        wrk.Close
                        
    
    Io penso che il problema possa dipendere dalla connessione wifi che ogni tanto salta, tenuto anche conto che l'ambiente è rumoroso (da un punto di vista elettrico) essendo un reparto di produzione con vari inverter di potenza elevata in funzione.

    Pensavo di intercettare l'errore e provare a rieseguire la procedura, se l'errore persiste volevo provare a rimuovere e ricollegare le tabelle, Se poi non funziona nemmeno così chiudere e riaprire access.
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Si se la connessione non è stabile... sicuramente può essere un problema...

    Se devi verificare la presenza non è un bellissimo sistema quello che fai... perchè in caso di Nessun Record... otterresti ERRORE il RecordCount non verrebbe eseguito.
    Oltretutto sai bene, dovresti saperlo, che la proprietà RecordCount non viene correttamente riconoscuiuta senza fare un Movelast...

    Ti suggerirei du usare una cosa simile:
    
     STRSQL = "SELECT TabellaRisorseAssegnate.Stato FROM TabellaRisorseAssegnate WHERE IdRecord=" & Me.Controls("IdRisorseAssegnate" & Indice) & ";"
                Set RstRisorse = db.OpenRecordset(STRSQL, dbOpenSnapshot)
                If RstRisorse.Eof And RstRisorse.Bof then
                    VarStato=0
                Else
                    VarStato = RstRisorse!stato
                End if
                RstRisorse.Close
    Sinceramente poi mi chiedo perchè non fare una Query PT... o una SP lato Server, che passando l'ID restituisce il valore...
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Non faccio una SP lato server perchè non sono molto esperto di SQL e non so farla negli ultimi anni ho sempre lavorato più su firmware in C/C++ e il VBA lo usavo solo per interfacciarmi a macchine utensili senza usare DB o al massimo giusto MDB di access, è una delle cose che devo imparare a fare appena trovo il tempo.

    Il codice con il recordcount l'ho scritto al volo per provare se poteva dipendere dalla dlookup non ci ho pensato più di tanto anche se ammetto che ero convinto che in caso di recorset vuoto ritornava zero e non errore.
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Come fa a valorizzare RecordCount se NON è accessibile la proprietà dal momento che l'Oggetto è VUOTO...?
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Buongiorno Alex, grazie per la sollecitudine e la competenza con cui rispondi a tutti noi.

    In questo caso però non sono d'accordo, con recordset vuoto la proprietà recordcount ritorna 0 senza generare errore.

    Questo codice di test a me funziona correttamente, se inserisco ID=1 cercando un record che non esiste in tabella recordcount ritorna 0 perchè il recordset è vuoto (in tabella nessun record ha id=1).

    Se inserisco Id=2 recordcount ritorna 1 (che solo casualmente è il numero di record restituito dalla query bisogna fare la movelast per avere il giusto conteggio dei record nel caso che la query restituisca più di un record) ad indicare che il recordset non è vuoto.
    rivate Sub Comando0_Click()
        Dim db As dao.Database
        Dim rst As dao.Recordset
        Dim STRSQL As String
    
        Set db = CurrentDb()
        STRSQL = "SELECT TabellaPerProve.Descrizione FROM TabellaPerProve WHERE Id=1;"
        Set rst = db.OpenRecordset(STRSQL, dbOpenSnapshot)
        If rst.RecordCount > 0 Then
            MsgBox (rst!descrizione)
        Else
            MsgBox (rst.RecordCount)
        End If
        rst.Close
        db.Close
        
    End Sub
    Questi sono i dati presenti nella tabella

    Id Descrizione Data
    2 ABC 01/01/1900 00:00:07
    3 ABC 02/02/2021 09:36:20
    4 ABC 02/03/2021 09:36:39
    5 ABC 03/02/2021 09:37:29
    6 ABC 17/02/2021 09:37:48
    7 ABC 28/01/2021 09:38:04
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Hai ragione sul RecordCount... confermo.
    Tuttavia non è corretto ugualmente l'utilizzo senza il MoveLast.
    Siccome mi pare che a te non serva nella realtà sapere quanti ma solo se esiste... l'utilizzo di BOF ed EOF, rimane a mio avviso il metodo più corretto e rapido, ma è un dettaglio che sicuramente sei in grado di discernere.
  • Re: Errore 3146 - ODBC: chiamata non riuscita

    Pienamente d'accordo con te, in questo caso mi serviva solo un test al volo per un programma che deve andare in mano agli utenti finali non è da fare.
Devi accedere o registrarti per scrivere nel forum
10 risposte