Solución alternativa a DCount y DLookup con MS SQL Server Backend
Uno de los principales problemas que hemos encontrado con Access es el uso de DLookup y DCount al usar tablas de SQL Server. Recientemente trabajamos en la migración de una solución de Access pura al servidor SQL y encontramos retrasos en la carga de varios formularios. Esto se debió al uso de DLookup y DCount en el código VBA.
Luego se nos ocurrió una solución para resolver rápidamente las múltiples instancias con un par de funciones. Nos guió otra solución proporcionada por Allen Browne, quien diseñó el DLookup extendido aquí en este enlace.
La solución de Allen mejora el rendimiento de DLookup al:
- Incluyendo un orden de clasificación para garantizar que obtenga el resultado que necesita.
- Limpiando después de sí mismo.
- Diferencia correctamente un nulo y una cadena de longitud cero.
- Mejora general en el rendimiento.
Ahora hemos dado un paso más para trabajar específicamente con tablas o vistas SQL, estas no funcionarán con tablas locales de Access ya que estamos usando específicamente una conexión ADO.
Incluyo el código para que ambas funciones reemplacen DLookup y 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
Si tiene una instancia que requiere el uso de DSum, puede adaptar fácilmente la función DCont para obtener el resultado requerido.
Después de aplicar esta solución, encontramos una mejora espectacular en el rendimiento de la carga de formularios y el diseño nos ayuda a aplicar esta solución a múltiples proyectos. Espero que esta solución le sea útil y si tiene algún otro problema con el que podamos ayudarlo, comuníquese con nosotros en accessexperts.com.