Solução alternativa para DCount e DLookup com back-end do MS SQL Server
Um dos principais problemas que encontramos com o Access é o uso de DLookup e DCount ao usar tabelas do SQL Server. Recentemente, trabalhamos na migração de uma solução de acesso puro para o SQL Server e encontramos atrasos no carregamento de vários formulários. Isso ocorreu devido ao uso de DLookup e DCount no código VBA.
Em seguida, criamos uma solução para resolver rapidamente as várias instâncias com algumas funções. Fomos guiados por outra solução fornecida por Allen Browne que projetou o Extended DLookup aqui neste link.
A solução de Allen melhora o desempenho do DLookup ao:
- Incluindo uma ordem de classificação para garantir que você obtenha o resultado necessário.
- Limpando sozinho.
- Diferencia corretamente uma string nula e uma string de comprimento zero.
- Melhoria geral no desempenho.
Agora demos um passo adiante para trabalhar especificamente com tabelas ou exibições SQL, elas não funcionarão com tabelas locais do Access, pois estamos usando especificamente uma conexão ADO.
Estou incluindo o código para ambas as funções para substituir DLookup e 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 você tiver uma instância que requer o uso de DSum, poderá adaptar facilmente a função DCount para fornecer o resultado necessário.
Depois de aplicar esta solução, encontramos uma melhoria dramática no desempenho do carregamento de formulários e o design nos ajuda a aplicar essa solução em vários projetos. Espero que esta solução seja útil para você e, se você tiver outros problemas com os quais possamos ajudá-lo, entre em contato conosco em accessexperts.com.