Pergunta

Eu quero comparar dois arquivos MS-Access mdb para verificar se os dados que eles contêm é o mesmo em ambos.

Como posso fazer isso?

Foi útil?

Solução

Eu fiz este tipo de coisa em muitos código, muitas vezes, principalmente nos casos em que um MDB locais necessários para ter atualizações aplicadas a ele elaborado a partir de dados inseridos em um site. Em um caso, o site foi impulsionado por um MDB, em outros, era um banco de dados MySQL. Para o MDB, nós apenas o download do mesmo, para o MySQL, corremos scripts no site para exportação e arquivos de texto FTP.

Agora o ponto principal é que nós queríamos para comparar os dados no MDB local para os dados baixados do site e atualizar o MDB local para refletir as alterações feitas no site (não, não era possível usar um único fonte de dados - foi a primeira coisa que eu sugeri, mas não foi possível)

.

Vamos chamada MDB A sua base de dados local, e MDB B o que você está baixando para comparação. O que você tem que verificar é:

  1. registros que existem no MDB A, mas não em MDB B. Estes podem ou não ser candidatos para eliminação (isso vai depender de seus dados particular).

  2. registros que existem no MDB B, mas não em MDB A. Estes você irá anexar do MDB B para MDB A.

  3. registros que existem em ambos, que terão de ser campo comparadas pelo campo.

Passos # 1 e # 2 são facilmente realizado com consultas que usam uma junção externa para encontrar os registros ausentes. Passo 3 requer algum código.

O princípio por trás do código é que a estrutura de todas as tabelas em ambos os MDBs são idênticos. Então, você usa DAO para caminhar a coleção TableDefs, abrir um conjunto de registros, e andar a coleção de campos para executar uma instrução SQL em cada coluna de cada tabela que ou atualiza os dados ou gera uma lista das diferenças.

A estrutura básica por trás do código é:

  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

Agora, a maior complexidade aqui é que seu cláusula WHERE para cada campo tem que ser diferente - campos de texto precisam ser tratados de forma diferente dos campos numéricos e de dados. Portanto, você provavelmente vai querer um SELECT CASE que escreve sua cláusula WHERE com base no tipo de campo:

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

Você vai querer usar Nz () para comparar os campos de texto, mas você pode usar Nz (TextField, '') para que, ao usar Nz (NumericField, 0) para campos numéricos ou campos de data.

Meu código exemplo não realmente usar a estrutura acima para definir a cláusula WHERE, porque ele é limitado aos campos que funcionam muito bem comparando concatenados com um ZLS (campos de texto). O que está abaixo é muito complicado para ler, mas é basicamente uma expansão na estrutura acima.

Foi escrito para a eficiência de atualizações, uma vez que executa um SQL UPDATE para cada campo da tabela, que é muito mais eficiente do que executar uma atualização do SQL para cada linha. Se, por outro lado, você não quer fazer uma atualização, mas quer uma lista das diferenças que você pode tratar a coisa toda de forma diferente. Mas isso fica muito complicado dependendo da saída,

Se tudo que você quer saber é se dois MDBs são idênticos, você deve primeiro verificar o número de registros em cada tabela em primeiro lugar, e se você tiver um não-jogo, você sair e dizer ao usuário que os MDBs não são o mesmo. Se os recordcounts são os mesmos, então você tem que verificar campo a campo, que eu acredito que é melhor realizado com coluna por coluna SQL escrita de forma dinâmica - assim como um dos resultando SQL SELECIONA retorna 1 ou mais registros, você abortar e informe o seu utilizador que os MDBs não são idênticas.

A parte complicada é que se você quer gravar as diferenças e informar o usuário, mas indo para que faria este post já interminável ainda mais!

O que se segue é apenas uma parte do código a partir de uma sub-rotina maior, que atualiza os qdfOldMembers consulta salva (de MDB A) com dados de qdfNewMembers (do MDB B). O primeiro argumento, strSQL, é uma instrução SELECT que se limita aos campos que deseja comparar, enquanto strTmpDB é o caminho / nome do arquivo do outro MDB (MDB B no nosso exemplo). O código assume que strTmpDB tem qdfNewMembers e qdfOldMembers já criado (o código original escreve o QueryDef salvo na mosca). Ele poderia facilmente ser nomes de tabela diretos (a única razão que eu uso uma consulta salva é porque os nomes de campos não correspondem exatamente entre os dois MDBs Foi escrito para).

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 a função varZLSToNull ():

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

Eu não sei se isso é demasiado complexo para fazer sentido, mas talvez ele vai ajudar alguém.

Outras dicas

Você pode tentar AccessDiff (produto pago). Ele tem a capacidade de comparar o esquema, os dados, e também objetos de acesso. Tem um GUI e também uma interface de linha de comando.

Divulgação:. Eu sou o criador desta ferramenta

Tome texto despejos de tabelas de banco de dados e simplesmente comparar os arquivos de texto de dumping utilizando BeyondCompare (ou qualquer outra ferramenta de comparação de texto). Bruto, mas pode trabalhar!

Eu tenho experiência muito boa com Cruz-Database Comparator . Ele é capaz de comparar a estrutura e / ou dados.

Veja a seção de bancos de dados Acesso Compare as Microsoft Access utilitários de terceiros, produtos, ferramentas , módulos, etc. página no meu site.

Eu adicionei recurso "mesa diff" para o meu accdbmerge utilidade não tão longo tempo atrás. Eu acredito que essa resposta não vai ajudar a resolver pergunta original, mas pode ser útil para alguém confrontado com o mesmo problema no futuro.

Se você quer saber se os arquivos são idênticos, em seguida,

fc file1.mdb file2.mdb 

em uma linha de comando do DOS.

Se os arquivos não são idênticos, mas você suspeitar que eles contêm as mesmas tabelas e registros, em seguida, a maneira mais fácil seria rapidamente escrever um pequeno utilitário que abre ambos os bancos de dados e ciclos através das mesas de ambos realizando uma consulta heterogénea para extrair o Diff entre os dois arquivos.

Existem algumas ferramentas lá fora, que vai fazer isso por você, mas todos eles parecem ser shareware.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top