Domanda

Voglio confrontare due file .mdb con accesso ms per verificare che i dati che contengono siano gli stessi in entrambi.

Come posso farlo?

È stato utile?

Soluzione

Ho fatto questo genere di cose nel codice molte, molte volte, soprattutto nei casi in cui un MDB locale aveva bisogno di applicare gli aggiornamenti a esso tratto dai dati inseriti su un sito Web. In un caso il sito Web era gestito da un MDB, in altri era un database MySQL. Per MDB, l'abbiamo appena scaricato, per MySQL, abbiamo eseguito script sul sito Web per esportare e file di testo FTP.

Ora, il punto principale è che volevamo confrontare i dati nell'MDB locale con i dati scaricati dal sito Web e aggiornare l'MDB locale per riflettere le modifiche apportate sul sito Web (no, non è stato possibile utilizzare un singolo origine dati: è stata la prima cosa che ho suggerito, ma non è stato possibile).

Chiamiamo MDB A il tuo database locale e MDB B quello che stai scaricando per il confronto. Quello che devi controllare è:

  1. record esistenti in MDB A ma non in MDB B. Questi possono o meno essere candidati alla cancellazione (questo dipenderà dai tuoi dati particolari).

  2. record esistenti in MDB B ma non in MDB A. Questi verranno aggiunti da MDB B a MDB A.

  3. record esistenti in entrambi, che dovranno essere confrontati campo per campo.

I passaggi n. 1 e n. 2 sono abbastanza facilmente realizzati con query che utilizzano un join esterno per trovare i record mancanti. Il passaggio 3 richiede del codice.

Il principio alla base del codice è che la struttura di tutte le tabelle in entrambi gli MDB è identica. Quindi, si utilizza DAO per eseguire il walk della raccolta TableDefs, aprire un recordset e camminare la raccolta dei campi per eseguire un'istruzione SQL su ciascuna colonna di ogni tabella che aggiorna i dati o genera un elenco delle differenze.

La struttura di base dietro il codice è:

  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

Ora, la maggiore complessità qui è che la clausola WHERE per ciascun campo deve essere diversa: i campi di testo devono essere trattati in modo diverso dai campi numerici e di dati. Quindi probabilmente vorrai un SELEZIONA CASO che scrive la tua clausola WHERE in base al tipo di campo:

  Select Case fld.Type
    Case dbText, dbMemo
    Case Else
  End Select

Ti consigliamo di usare Nz () per confrontare i campi di testo, ma per questo utilizzeresti Nz (TextField, ''), mentre usi Nz (NumericField, 0) per campi numerici o campi data.

Il mio codice di esempio in realtà non utilizza la struttura sopra per definire la clausola WHERE perché è limitata ai campi che funzionano molto bene confrontando concatenati con uno ZLS (campi di testo). Quello che segue è piuttosto complicato da leggere, ma è fondamentalmente un'espansione della struttura sopra.

È stato scritto per l'efficienza degli aggiornamenti, poiché esegue un aggiornamento SQL per ogni campo della tabella, che è molto più efficiente dell'esecuzione di un aggiornamento SQL per ogni riga. Se, d'altra parte, non vuoi fare un aggiornamento, ma vuoi un elenco delle differenze, potresti trattare l'intera cosa in modo diverso. Ma questo diventa piuttosto complicato a seconda dell'output,

Se tutto ciò che vuoi sapere è se due MDB sono identici, dovresti prima controllare il numero di record in ciascuna tabella e se hai una non corrispondenza, esci e dici all'utente che gli MDB non lo sono lo stesso. Se i conteggi dei record sono gli stessi, allora devi controllare campo per campo, che credo sia meglio realizzare con SQL colonna per colonna scritto in modo dinamico - non appena uno degli SQL SELECTS risultanti restituisce 1 o più record, interrompi e comunica al tuo utente che gli MDB non sono identici.

La parte complicata è se si desidera registrare le differenze e informare l'utente, ma approfondire ciò renderebbe questo post già interminabile ancora più lungo!

Quello che segue è solo una parte del codice di una subroutine più grande che aggiorna la query salvata qdfOldMembers (da MDB A) con i dati da qdfNewMembers (da MDB B). Il primo argomento, strSQL, è un'istruzione SELECT limitata ai campi che si desidera confrontare, mentre strTmpDB è il percorso / nome file dell'altro MDB (MDB B nel nostro esempio). Il codice presuppone che strTmpDB abbia già creato qdfNewMembers e qdfOldMembers (il codice originale scrive al volo il QueryDef salvato). Potrebbe essere altrettanto facile essere nomi di tabella diretti (l'unica ragione per cui utilizzo una query salvata è perché i nomi dei campi non corrispondono esattamente tra i due MDB per cui è stato scritto).

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

Codice per la funzione varZLSToNull ():

Public Function varZLStoNull(varInput As Variant) As Variant
  If Len(varInput) = 0 Then
     varZLStoNull = Null
  Else
     varZLStoNull = varInput
  End If
End Function

Non so se sia troppo complesso per avere un senso, ma forse aiuterà qualcuno.

Altri suggerimenti

Puoi provare AccessDiff (prodotto a pagamento). Ha la capacità di confrontare lo schema, i dati e anche gli oggetti di accesso. Ha una GUI e anche un'interfaccia a riga di comando.

Divulgazione: sono il creatore di questo strumento.

Prendi i dump di testo delle tabelle del database e confronta semplicemente i file di testo scaricati usando BeyondCompare (o qualsiasi altro strumento di confronto del testo). Crudo ma può funzionare!

Ho un'ottima esperienza con Comparatore tra database diversi . È in grado di confrontare struttura e / o dati.

Consulta la sezione Confronta i database di Access in Utilità, prodotti e strumenti di terze parti di Microsoft Access , moduli, ecc. sul mio sito Web.

Ho aggiunto " table diff " funzione della mia accdbmerge non molto tempo fa. Credo che questa risposta non aiuterà a risolvere la domanda originale, ma potrebbe essere utile per qualcuno che dovrà affrontare lo stesso problema in futuro.

Se vuoi sapere se i file sono identici, allora

fc file1.mdb file2.mdb 

su una riga comandi DOS.

Se i file non sono identici ma si sospetta che contengano le stesse tabelle e record, il modo più semplice sarebbe quello di scrivere rapidamente una piccola utility che apre entrambi i database e scorre le tabelle di entrambi eseguendo una query eterogenea per estrarre il Diff tra i due file.

Ci sono alcuni strumenti là fuori che lo faranno per te, ma sembrano tutti shareware.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top