Soluzione alternativa a DCount e DLookup con il backend di MS SQL Server
Uno dei problemi principali che abbiamo riscontrato con Access è l'uso di DLookup e DCount quando si utilizzano le tabelle di SQL Server. Di recente abbiamo lavorato alla migrazione di una soluzione di accesso puro al server SQL e abbiamo riscontrato ritardi nel caricamento di diversi moduli. Ciò era dovuto all'uso di DLookup e DCount nel codice VBA.
Abbiamo quindi trovato una soluzione per risolvere rapidamente le istanze multiple con un paio di funzioni. Siamo stati guidati da un'altra soluzione fornita da Allen Browne che ha progettato Extended DLookup qui in questo link.
La soluzione di Allen migliora le prestazioni di DLookup:
- Incluso un ordinamento per assicurarti di ottenere il risultato di cui hai bisogno.
- Pulizia dopo se stessa.
- Distingue correttamente una stringa Null e una stringa di lunghezza zero.
- Miglioramento generale delle prestazioni.
Ora abbiamo fatto un ulteriore passo avanti per lavorare in modo specifico con tabelle o viste SQL, queste non funzioneranno con le tabelle locali di Access poiché stiamo utilizzando specificamente una connessione ADO.
Sto includendo il codice per entrambe le funzioni per sostituire sia DLookup che DCount
Public Function ESQLLookup(strField As String, strTable As String, Optional Criteria As Variant, _ Optional OrderClause As Variant) As Variant Dim rs As ADODB.Recordset 'To retrieve the value to find. Dim rsMVF As ADODB.Recordset 'Child recordset to use for multi-value fields. Dim varResult As Variant 'Return value for function. Dim strSQL As String 'SQL statement. Dim strOut As String 'Output string to build up (multi-value field.) Dim lngLen As Long 'Length of string. Const strcSep = "," 'Separator between items in multi-value list. 'Initialize to null. varResult = Null 'Encapsulate Domain in brackets if none exist to allow special characters in the Domain string If Left$(strTable, 1) <> "[" Then strTable = "[" & strTable & "]" End If 'Build the SQL string. strSQL = "SELECT TOP 1 " & strField & " FROM " & strTable If Not IsMissing(Criteria) Then strSQL = strSQL & " WHERE " & Criteria End If If Not IsMissing(OrderClause) Then strSQL = strSQL & " ORDER BY " & OrderClause End If strSQL = strSQL & ";" 'Lookup the value. OpenMyRecordset rs, strSQL, rrOpenForwardOnly, rrLockReadOnly, True If rs.RecordCount > 0 Then 'Will be an object if multi-value field. If VarType(rs(0)) = vbObject Then Set rsMVF = rs(0).Value Do While Not rsMVF.EOF If rs(0).Type = 101 Then 'dbAttachment strOut = strOut & rsMVF!FileName & strcSep Else strOut = strOut & rsMVF![Value].Value & strcSep End If rsMVF.MoveNext Loop 'Remove trailing separator. lngLen = Len(strOut) - Len(strcSep) If lngLen > 0& Then varResult = Left(strOut, lngLen) End If Set rsMVF = Nothing Else 'Not a multi-value field: just return the value. varResult = rs(0) End If End If rs.Close 'Assign the return value. ESQLLookup = varResult ErrEx.Catch 11 ' Division by Zero Debug.Print strSQL MsgBox "To troubleshoot this error, please evaluate the data that is being processed by:" _ & vbCrLf & vbCrLf & strSQL, vbCritical, "Division by Zero Error" ErrEx.CatchAll MsgBox "Error " & err.Number & ": " & err.Description, vbCritical, "Unexpected error" ErrEx.Finally Set rs = Nothing End Function
Public Function ESQLCount(strField As String, strTable As String, Optional Criteria As Variant) As Variant Dim rs As ADODB.Recordset 'To retrieve the value to find. Dim varResult As Variant 'Return value for function. Dim strSQL As String 'SQL statement. Dim lngLen As Long 'Length of string. 'Initialize to null. varResult = Null 'Encapsulate Domain in brackets if none exist to allow special characters in the Domain string If Left$(strTable, 1) <> "[" Then strTable = "[" & strTable & "]" End If 'Build the SQL string. strSQL = "SELECT COUNT(" & strField & ") AS TotalCount FROM " & strTable If Not IsMissing(Criteria) Then strSQL = strSQL & " WHERE " & Criteria End If strSQL = strSQL & ";" 'Lookup the value. OpenMyRecordset rs, strSQL, rrOpenForwardOnly, rrLockReadOnly, True varResult = Nz(rs.Fields("TotalCount"), 0) rs.Close 'Assign the return value. ESQLCount = varResult ErrEx.CatchAll MsgBox "Error " & err.Number & ": " & err.Description, vbCritical, "Unexpected error" Resume Next ErrEx.Finally Set rs = Nothing End Function
Se hai un'istanza che richiede l'uso di DSum, puoi facilmente adattare la funzione DCount per darti il risultato richiesto.
Dopo aver applicato questa soluzione, abbiamo riscontrato un notevole miglioramento nelle prestazioni del caricamento dei moduli e il design ci aiuta ad applicare questa soluzione a più progetti. Spero che questa soluzione ti sia utile e se hai altri problemi con cui possiamo aiutarti, contattaci su accessexperts.com.