|
まず、2つのテーブルが同じであると判断する基準を整理しておきましょう。
- フィールド数が同じである。
- フィールドの順序が同じである。
- 個々のフィールド定義が同じである。
- レコード数が同じである。
- すべてのレコードのデータ内容が同じである。
T'sKitではこのうち3番目の比較は行っていません。フィールドの定義項目としては、テキスト型のフィールドサイズや書式、定型入力、既定値、入力規則といったものがありますが、厳密に「2つのテーブルが同じである」というためにはもちろんこのチェックは欠かせません。 |
例えば、処理の中でデータ定義クエリーなどを使ってテーブルを作成しているような場合には、そのクエリーが修正前のクエリーと同じテーブルを作成しているか、それらのフィールド定義の内容も比べてみることが必要となります。しかし、T'sKitの「テーブル/クエリー比較」ツールを使用する場面としては、基本的にデータを生成するVBAコードの修正前後の比較を想定していますので、"故意にテーブル構造が変えられることはない"、という前提で、ここまでの比較には踏み込んでいません。
それでは、上記の1、2、4、5の判断基準について、1つずつコードを説明していきたいと思います。 |
|
最初に、変数の宣言を行い、続いてすべての比較項目に先立って2つのテーブルを開きます。ここでは"テーブル1"と"テーブル2"という名前の2つのテーブルを比較してみます。実際にはこれらはテーブルを比較するプロシージャの引数にするべきものです。 |
Dim dbs As Database
Dim rst1 As Recordset, rst2 As Recordset
Dim lngRecMax1 As Long, lngRecMax2 As Long
Dim lngReadRecords As Long
Dim intFldCount As Integer
Set dbs = CurrentDb
Set rst1 = dbs.OpenRecordset("テーブル1")
Set rst2 = dbs.OpenRecordset("テーブル2")
|
|
それでは最初の比較項目として「フィールド数の比較」を行ってみましょう。これを最初に比較するのは、コードを見れば分かるように、Recordset
オブジェクトがすでに開かれている状態では [Fields]オブジェクト の [Count]プロパティ を見ることによって直ちに比較することができるからです。複数のフィールドを調べたり複数のレコードを調べたりする必要がありませんので、最も速くテーブル間の違いを検出することができます。これを最初に比較することによって2つのテーブルに違いがあった場合にいち早くそれを知らせることができるわけです。
If rst1.Fields.Count <> rst2.Fields.Count Then
Beep
MsgBox "2つのテーブル/クエリーは構造(フィールドの数)が異なります!", _
vbOKOnly + vbInformation
GoSub AllClose
'このサブルーチンはテーブル比較のために開いたすべてのテーブルを閉じるものです
Exit Sub
End If |
続いて「フィールド名の比較」を行います。フィールド名もフィールド定義の1つですので、このツールの利用前提からすれば不要なのですが、次のコードのように比較することによって、フィールドの順序も合わせて比較できますので、T'sKitでは一応確認を行っています。
[Fields]オブジェクト の [Count]プロパティ は、そのテーブルのフィールド数を取得するものですが、最初のフィールドは"0"から数え始めますので、0
〜 (rst1.Fields.Count - 1) のループによって各フィールドを先頭から順番に参照していきます。そして、"rst1.Fields(intFldCount).Name"
がintFldCount番目のフィールドの[名前]を返しますので、両者の比較を行い、違いがあればメッセージを表示します。
For intFldCount = 0 To rst1.Fields.Count - 1
If rst1.Fields(intFldCount).Name <> _
rst2.Fields(intFldCount).Name Then
Beep
MsgBox("2つのテーブル/クエリーは構造(フィールド名)が異なります!", _
vbOKOnly + vbInformation
GoSub AllClose
Exit Sub
End If
Next intFldCount |
|
続いて、各レコードにアクセスしてレコードの比較を行っていきます。まず最初は「レコード数の比較」です。
lngRecMax1 = tscl_RecCount(rst1)
lngRecMax2 = tscl_RecCount(rst2)
If lngRecMax1 <> lngRecMax2 Then
Beep
MsgBox "2つのテーブル/クエリーはレコード数が異なります!" & vbCrLf _
"テーブル1 → " & lngRecMax1 & " レコード" & vbCrLf & _
"テーブル2 → " & lngRecMax2 & " レコード", _
vbOKOnly + vbInformation
GoSub AllClose
Exit Sub
End If
このコードで呼び出されている "tscl_RecCount" Functionプロシージャは、引数として与えられたRecordsetオブジェクトのレコード数を返します。レコード数を得るに[RecordCount]プロパティ値を参照しますが、このプロパティはあくまでもアクセスされたレコード数を返しますので、いったん最後のレコードまで移動してからその値を取得するようにします。
Public Function tscl_RecCount(rst As Recordset) As Long
On Error Resume Next
With rst
.MoveLast
tscl_RecCount = .RecordCount
.MoveFirst
End With
End Function
|
|
最後にすべてのレコードの「データ内容の比較」を行います。すべてのデータを比較するということは、"すべてのレコードについてすべてのフィールドの値を比較する"ということですので、まず外側に全レコードを読み込むループを作り、その内側にいわゆる入れ子状に全フィールド値を読み込むループを作ります。すでにそのテーブルのレコード数は変数
lngRecMax1 として得られていますので、それを外側のループの上限とします。また、内側のループ構造は各フィールドの名前を取得した場合と同じです。フィールド名があらかじめ分かっている場合には
rst!フィールド名 のような構文でフィールドの値を得ることができますが、ここではさまざまなテーブルを比較できるようにする必要があるため、固定的なフィールド名は使用できません。そこでここでは、[Value]プロパティを使ってそのフィールドに格納された値を取得し、両者のテーブルを比較していきます。コードは次のようになります。
For lngReadRecords = 1 To lngRecMax1
For intFldCount = 0 To rst1.Fields.Count - 1
If rst1.Fields(intFldCount).Value <> rst2.Fields(intFldCount).Value Then
Beep
MsgBox "2つのテーブル/クエリーに違いが見つかりました!" & vbCrLf & _
"レコード番号 → " & lngReadRecords & vbCrLf & _
"フィールド名 → " & rst1.Fields(intFldCount).Name & vbCrLf & _
"テーブル1 → " & rst1.Fields(intFldCount).Value & vbCrLf & _
"テーブル2 → " & rst2.Fields(intFldCount).Value, _
vbOKOnly + vbInformation
GoSub AllClose
Exit Sub
End If
Next intFldCount
rst1.MoveNext: rst2.MoveNext
Next lngReadRecords |