¿Puedo comparar dos archivos de acceso ms? [cerrado]
Pregunta
Quiero comparar dos archivos ms-access .mdb para verificar que los datos que contienen son los mismos en ambos.
¿Cómo puedo hacer esto?
Solución
He hecho este tipo de cosas en el código muchas, muchas veces, principalmente en los casos en que un MDB local necesitaba que se le aplicaran actualizaciones extraídas de los datos ingresados ??en un sitio web. En un caso, el sitio web estaba dirigido por un MDB, en otros, era una base de datos MySQL. Para el MDB, lo acabamos de descargar, para MySQL, ejecutamos scripts en el sitio web para exportar y enviar archivos de texto FTP.
Ahora, el punto principal es que queríamos comparar los datos en el MDB local con los datos descargados del sitio web y actualizar el MDB local para reflejar los cambios realizados en el sitio web (no, no fue posible utilizar una sola Fuente de datos: fue lo primero que sugerí, pero no fue factible).
Llamemos a MDB A su base de datos local, y a MDB B la que está descargando para comparar. Lo que tienes que verificar es:
-
registros que existen en MDB A pero no en MDB B. Estos pueden o no ser candidatos para su eliminación (esto dependerá de sus datos particulares).
-
registros que existen en MDB B pero no en MDB A. Estos se adjuntarán de MDB B a MDB A.
-
registros que existen en ambos, que deberán compararse campo por campo.
Los pasos # 1 y # 2 se realizan con bastante facilidad con consultas que usan una combinación externa para encontrar los registros faltantes. El paso 3 requiere algo de código.
El principio detrás del código es que la estructura de todas las tablas en ambos MDB es idéntica. Por lo tanto, utiliza DAO para recorrer la colección TableDefs, abrir un conjunto de registros y recorrer la colección de campos para ejecutar una declaración SQL en cada columna de cada tabla que actualiza los datos o genera una lista de las diferencias.
La estructura básica detrás del código es:
Set rs = db.OpenRecordset("[SQL statement with the fields you want compared]")
For Each fld In rs.Fields
' Write a SQL string to update all the records in this column
' where the data doesn't match
strSQL = "[constructed SQL here]"
db.Execute strSQL, dbFailOnError
Next fld
Ahora, la mayor complejidad aquí es que su cláusula WHERE para cada campo debe ser diferente: los campos de texto deben tratarse de manera diferente a los campos numéricos y de datos. Así que probablemente querrá un CASO SELECCIONADO que escriba su cláusula WHERE según el tipo de campo:
Select Case fld.Type
Case dbText, dbMemo
Case Else
End Select
Querrá usar Nz () para comparar los campos de texto, pero usaría Nz (TextField, '') para eso, mientras usa Nz (NumericField, 0) para campos numéricos o campos de fecha.
El código de mi ejemplo no usa realmente la estructura anterior para definir la cláusula WHERE porque se limita a los campos que funcionan muy bien en comparación concatenados con un ZLS (campos de texto). Lo que está debajo es bastante complicado de leer, pero es básicamente una expansión en la estructura anterior.
Fue escrito para la eficiencia de las actualizaciones, ya que ejecuta una ACTUALIZACIÓN SQL para cada campo de la tabla, que es mucho más eficiente que ejecutar una ACTUALIZACIÓN SQL para cada fila. Si, por otro lado, no desea hacer una actualización, pero desea una lista de las diferencias, puede tratar todo el asunto de manera diferente. Pero eso se complica bastante dependiendo de la salida,
Si todo lo que quiere saber es si dos MDB son idénticos, primero debe verificar el número de registros en cada tabla, y si tiene una no coincidencia, abandona y le dice al usuario que los MDB no están lo mismo. Si las cuentas de registro son iguales, entonces debe verificar campo por campo, lo que creo que se logra mejor con el SQL columna por columna escrito dinámicamente, tan pronto como uno de los SELECTOS de SQL resultantes devuelve 1 o más registros, usted abortará y dígale a su usuario que los MDB no son idénticos.
La parte complicada es si quieres registrar las diferencias e informar al usuario, pero si entiendes eso, esta publicación ya interminable será aún más larga.
Lo que sigue es solo una parte del código de una subrutina más grande que actualiza la consulta guardada qdfOldMembers (de MDB A) con datos de qdfNewMembers (de MDB B). El primer argumento, strSQL, es una declaración SELECT que se limita a los campos que desea comparar, mientras que strTmpDB es la ruta / nombre de archivo de los otros MDB (MDB B en nuestro ejemplo). El código supone que strTmpDB tiene qdfNewMembers y qdfOldMembers ya creados (el código original escribe el QueryDef guardado sobre la marcha). Podría ser igual de fácil que sean nombres de tabla directos (la única razón por la que uso una consulta guardada es porque los nombres de campo no coinciden exactamente entre los dos MDB para los que se escribió).
Public Sub ImportMembers(strSQL As String, strTmpDB As String)
Const STR_QUOTE = """"
Dim db As Database
Dim rsSource As Recordset '
Dim fld As Field
Dim strUpdateField As String
Dim strZLS As String
Dim strSet As String
Dim strWhere As String
' EXTENSIVE CODE LEFT OUT HERE
Set db = Application.DBEngine(0).OpenDatabase(strTmpDB)
' UPDATE EXISTING RECORDS
Set rsSource = db.OpenRecordset(strSQL)
strSQL = "UPDATE qdfNewMembers INNER JOIN qdfOldMembers ON "
strSQL = strSQL & "qdfNewMembers.EntityID = qdfOldMembers.EntityID IN '" _
& strTmpDB & "'"
If rsSource.RecordCount <> 0 Then
For Each fld In rsSource.Fields
strUpdateField = fld.Name
'Debug.Print strUpdateField
If InStr(strUpdateField, "ID") = 0 Then
If fld.Type = dbText Then
strZLS = " & ''"
Else
strZLS = vbNullString
End If
strSet = " SET qdfOldMembers." & strUpdateField _
& " = varZLStoNull(qdfNewMembers." & strUpdateField & ")"
strWhere = " WHERE " & "qdfOldMembers." & strUpdateField & strZLS _
& "<>" & "qdfNewMembers." & strUpdateField & strZLS _
& " OR (IsNull(qdfOldMembers." & strUpdateField _
& ")<>IsNull(varZLStoNull(qdfNewMembers." _
& strUpdateField & ")));"
db.Execute strSQL & strSet & strWhere, dbFailOnError
'Debug.Print strSQL & strSet & strWhere
End If
Next fld
End If
End Sub
Código para la función varZLSToNull ():
Public Function varZLStoNull(varInput As Variant) As Variant
If Len(varInput) = 0 Then
varZLStoNull = Null
Else
varZLStoNull = varInput
End If
End Function
No sé si eso es demasiado complejo para tener sentido, pero tal vez ayude a alguien.
Otros consejos
Puede probar AccessDiff (producto pagado). Tiene la capacidad de comparar el esquema, los datos y también acceder a los objetos. Tiene una GUI y también una interfaz de línea de comandos.
Divulgación: Soy el creador de esta herramienta.
Tome volcados de texto de tablas de bases de datos y simplemente compare los archivos de texto volcados utilizando BeyondCompare (o cualquier otra herramienta de comparación de texto). ¡Crudo pero puede funcionar!
Tengo muy buena experiencia con Comparador de bases de datos cruzadas . Es capaz de comparar estructura y / o datos.
Consulte la sección de bases de datos Compare Access en Utilidades, productos y herramientas de terceros de Microsoft Access , módulos, etc. en mi sitio web.
He agregado " tabla diff " función para mi accdbmerge no hace mucho tiempo. Creo que esta respuesta no ayudará a resolver la pregunta original, pero puede ser útil para alguien que tenga el mismo problema en el futuro.
Si desea saber si los archivos son idénticos, entonces
fc file1.mdb file2.mdb
en una línea de comando de DOS.
Si los archivos no son idénticos pero sospecha que contienen las mismas tablas y registros, entonces la forma más fácil sería escribir rápidamente una pequeña utilidad que abra las bases de datos y los ciclos a través de las tablas de ambos realizando una consulta heterogénea para extraer el Diff entre los dos archivos.
Hay algunas herramientas por ahí que harán esto por ti, pero todas parecen ser shareware.