Access VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


370 / 2272 ツリー ←次へ | 前へ→

【11993】二つのテーブルを比較する方法 KANA 11/5/20(金) 9:09 質問[未読]
【11995】Re:二つのテーブルを比較する方法 小僧 11/5/23(月) 11:49 発言[未読]
【11997】Re:二つのテーブルを比較する方法 KANA 11/5/23(月) 15:18 質問[未読]
【11998】Re:二つのテーブルを比較する方法 小僧 11/5/23(月) 16:17 回答[未読]
【11999】Re:二つのテーブルを比較する方法 KANA 11/5/24(火) 16:12 質問[未読]
【12000】Re:二つのテーブルを比較する方法 小僧 11/5/25(水) 12:12 発言[未読]
【12001】Re:二つのテーブルを比較する方法 KANA 11/5/25(水) 17:22 お礼[未読]

【11993】二つのテーブルを比較する方法
質問  KANA  - 11/5/20(金) 9:09 -

引用なし
パスワード
   二つのテーブル新TBLと旧TBLが存在します。
この二つのテーブルは全く同じ項目が載っているわけではないので、必要な項目列だけをチェックしたいと思っています

二つのデーブルを比較して、新と旧で中身が変更となっているものはどれなのか?を調べ、
変更TBLに変更を生じた箇所だけをリストアップしていきたいと思ってます。

下記のように作ってみたのですが、途中でどうしてもエラーとなってしまい、先へ進まず悩んでます。

If Mydic.Item(strKey)(u) <> MyVal2(u) Then ’←ココでエラーがでます。(オブジェクトが有効ではありません)

どうかご教授お願いします。
Dictionaryオブジェクトの使い方が間違っているのでしょうか?

Option Compare Database

Sub ChangeData()

'変更した箇所のチェック

Dim rs As ADODB.Recordset
Dim rst As ADODB.Recordset
Dim rsC As ADODB.Recordset
Dim MyVal, MyVal2, MyVal3, MyVal4
Dim lCnt As Long
Dim Mydic As Object
Dim Dic_Change As Object
Dim strKey As String
Dim DC As Long


Set Mydic = CreateObject("scripting.dictionary")
Set Dic_Change = CreateObject("scripting.dictionary")


Set rs = New ADODB.Recordset
  rs.CursorType = adOpenKeyset
  rs.LockType = adLockReadOnly

Set rst = New ADODB.Recordset
  rst.CursorType = adOpenKeyset
  rst.LockType = adLockReadOnly
  
Set rsC = New ADODB.Recordset
  rsC.CursorType = adOpenKeyset
  rsC.LockType = adLockOptimistic


rs.Open "新TBL", CurrentProject.Connection, , adCmdTable
rst.Open "旧TBL", CurrentProject.Connection, , adCmdTable
rsC.Open "変更List", CurrentProject.Connection, , adCmdTable


旧TBLにデータがあったら差異箇所をチェック
DC = rst.RecordCount

If DC > 0 Then


’新TBLのデータをDictionaryオブジェクトを使用してデータを取得

rs.MoveFirst

Do Until rs.EOF
 strKey = rs![KEY]
If Not Mydic.Exists(strKey) Then
  MyVal = Array(rs![F1], rs![F2], rs![F3], rs![F4], rs![F5], rs![F6], rs![F7], _
        rs![F8], rs![F10], rs![F11], rs![F12], rs![F13], rs![F14], rs![F17])
       
  Mydic.Add strKey, MyVal
 
 End If
 rs.MoveNext
Loop

rs.Close
Set rs = Nothing

’もし、新データと同じKeyがあったら、旧データを配列格納し、新データと旧データを比較し、違うものがあれば、新データの値を配列格納し、同じ場合は、””値を格納する
rst.MoveFirst

Do Until rst.EOF
 strKey = rst![KEY]
 If Mydic.Exists(strKey) Then
   MyVal2 = Array(rst![F2], rst![F3], rst![F4], rst![F5], rst![F6], rst![F7], rst![F8], _
        rst![F10], rst![F11], rst![F12], rst![F13], rst![F14], rst![F15], rst![F16])
    

    If Mydic.Exists(strKey) Then
     For u = 0 To UBound(MyVal2)
      
      If Mydic.Item(strKey)(u) <> MyVal2(u) Then ’←ココでエラーがでます。(オブジェクトが有効ではありません)
        lCnt = UBound(MyVal3)
        ReDim Preserve MyVal3(lCnt)
        MyVal3(lCnt) = Mydic.Item(strKey)(u)’新データを格納
       Else
        lCnt = UBound(MyVal3)
        ReDim Preserve MyVal3(lCnt)
        MyVal3(lCnt) = "" ’空白を格納
       End If
     Next u
    End If
   
   Dic_Change.Add strKey, MyVal3
  
  
 End If
 rst.MoveNext
Loop
rst.Close
Set rst = Nothing

Dim MyKey, MyItem

MyKey = Dic_Change.Keys
MyItem = Dic_Change.Items


For i = 0 To UBound(MyKey)
rsC.AddNew
  MyVal4 = Array(rsC![F2], rsC![F3], rsC![F4], rsC![F5], rsC![F6], rsC![F7], _
        rsC![F8], rsC![F9], rsC![F10], rsC![F11], rsC![F12], rsC![F13], rsC![F14], rsC![F15])
 
  rsC![F1] = MyKey(i)
  For u = 0 To UBound(MyVal4)
   rsC!MyVal4(u) = Dic_Change(MyKey(u))(u)
  Next u
  rsC.Update
Next i

  rsC.Close
  Set rsC = Nothing

Else

rs.Close
Set rs = Nothing
rst.Close
Set rst = Nothing
rsC.Close
Set rsC = Nothing


End If

End Sub

【11995】Re:二つのテーブルを比較する方法
発言  小僧  - 11/5/23(月) 11:49 -

引用なし
パスワード
   ▼KANA さん:
こんにちは。

普段Accessでコードを書いていると陥りがちな
暗黙の型変換に問題がありそうですね。

下記の様なコードをテストして
Dictionaryオブジェクトに格納される値を確認されてみて下さい。


Sub TypeNameTest()
Dim rs As ADODB.Recordset
Dim MyDic As Object

  Set MyDic = CreateObject("Scripting.Dictionary")
  Set rs = New ADODB.Recordset
    rs.CursorType = adOpenKeyset
    rs.LockType = adLockReadOnly

    rs.Open "新TBL", CurrentProject.Connection, , adCmdTable

    If rs.EOF Then
      MsgBox "データ入ってないよ!"
      Exit Sub
    Else
            
      MyDic.Add "1", rs(0)
      MyDic.Add "2", rs(0).Value
            
      Debug.Print TypeName(MyDic("1"))
      Debug.Print TypeName(MyDic("2"))
            
    End If
  rs.Close: Set rs = Nothing
  Set MyDic = Nothing
  
End Sub

【11997】Re:二つのテーブルを比較する方法
質問  KANA  - 11/5/23(月) 15:18 -

引用なし
パスワード
   ▼小僧 さん:

頂いたコードを記述してみてみました。

>      MyDic.Add "1", rs(0)
>      MyDic.Add "2", rs(0).Value

上記の部分で rs(0)とrs(0).value の意味がいまいちわかりませんので教えていただけないでしょうか?

rs(0)のほうはFieldとでてきてて、rs(0).valueはタイプがでてきていたのですが、
Fieldはなにを指してくれているのか?わからない状態です。
タイプのほうは、値が入っていないとNullとなるのですね?

あと、For i をつかって、すべてのフィールドをチェックしてみようとすると、
  今まで、Nullやタイプ型など取得してきてくれるのに、全部Emptyとなってしまいます。

Accessで、こういうことをやる場合は、Dictionaryはあまり使わないほうがいいのでしょうか?

すみませんが、初心者のため、つまづきまくってます。

どうか、伝授よろしくお願いします

 
>▼KANA さん:
>こんにちは。
>
>普段Accessでコードを書いていると陥りがちな
>暗黙の型変換に問題がありそうですね。
>
>下記の様なコードをテストして
>Dictionaryオブジェクトに格納される値を確認されてみて下さい。
>
>
>Sub TypeNameTest()
>Dim rs As ADODB.Recordset
>Dim MyDic As Object
>
>  Set MyDic = CreateObject("Scripting.Dictionary")
>  Set rs = New ADODB.Recordset
>    rs.CursorType = adOpenKeyset
>    rs.LockType = adLockReadOnly
>
>    rs.Open "新TBL", CurrentProject.Connection, , adCmdTable
>
>    If rs.EOF Then
>      MsgBox "データ入ってないよ!"
>      Exit Sub
>    Else
>            
>      MyDic.Add "1", rs(0)
>      MyDic.Add "2", rs(0).Value
>            
>      Debug.Print TypeName(MyDic("1"))
>      Debug.Print TypeName(MyDic("2"))
>            
>    End If
>  rs.Close: Set rs = Nothing
>  Set MyDic = Nothing
>  
>End Sub

【11998】Re:二つのテーブルを比較する方法
回答  小僧  - 11/5/23(月) 16:17 -

引用なし
パスワード
   ▼KANA さん:
こんにちは。

>>      MyDic.Add "1", rs(0)
>>      MyDic.Add "2", rs(0).Value
>
> 上記の部分で rs(0)とrs(0).value の意味が
> いまいちわかりませんので教えていただけないでしょうか?

ごめんなさい。
KANAさんの記述を使うと

Midic.Add "1", rs![F1]
Midic.Add "2", rs![F1].Value

の方が解りやすかったですね。

rs(0) は rs の一番初めのフィールドを表しています。


>rs(0)のほうはFieldとでてきてて

rs![F1] をDictionary オブジェクトの Item 値に代入すると
rs![F1] の値ではなく、ADODB.Recordset で定義されている
フィールドオブジェクトへの参照を代入してしまっている事を意味します。

初めに投稿されたコードですと、

>>> rs.Close
>>> Set rs = Nothing

の箇所で rs への参照が切れてしまっている為、
フィールドも参照できなくなりエラーが発生しております。

値だけをDictionaryオブジェクトに入力するのであれば
rs![F1].Value と明示的に指定しなければいけないという事です。


KANAさんのコードをそのまま生かすとなると、

>  MyVal = Array(rs![F1], rs![F2], rs![F3], rs![F4], rs![F5], rs![F6], rs![F7], _
>        rs![F8], rs![F10], rs![F11], rs![F12], rs![F13], rs![F14], rs![F17])

  MyVal = Array(rs![F1].Value, rs![F2].Value, rs![F3].Value, rs![F4].Value, rs![F5].Value, rs![F6].Value, rs![F7].Value, _
        rs![F8].Value, rs![F10].Value, rs![F11].Value, rs![F12].Value, rs![F13].Value, rs![F14].Value, rs![F17].Value)

となりますね。


> Accessで、こういうことをやる場合は、
> Dictionaryはあまり使わないほうがいいのでしょうか?

当方でしたら、SQLで片づけてしまうかと思われます。
提示されたコードのうち、左3つを比較するSQLでしたら

SELECT
  旧TBL.key
 , IIf([旧TBL]![F1]=[新TBL]![F2],"",[新TBL]![F2]) AS 比較1
 , IIf([旧TBL]![F2]=[新TBL]![F3],"",[新TBL]![F3]) AS 比較2
 , IIf([旧TBL]![F3]=[新TBL]![F4],"",[新TBL]![F4]) AS 比較3
FROM
  旧TBL
INNER JOIN
  新TBL
ON 旧TBL.key = 新TBL.key
WHERE NOT(
     ([旧TBL]![F1]=[新TBL]![F2])
   AND ([旧TBL]![F2]=[新TBL]![F3]) 
   AND ([旧TBL]![F3]=[新TBL]![F4])
         )


上記のSQLをクエリのSQLビューに張り付け実行すると
結果が出るかと思われます。
(コピーペーストする際は
 全角スペースは半角スペースに変換して下さい)

ただ、自分に慣れている方法で結果を出すことは
決して悪い事だと思いませんので
まずはコードの問題を解決した後
ご興味があればSQLにも挑戦されてみてはいかがでしょうか。

【11999】Re:二つのテーブルを比較する方法
質問  KANA  - 11/5/24(火) 16:12 -

引用なし
パスワード
   ▼小僧 さん:

とても分かりやすいアドバイスをありがとうございました。
言われたとおりに、Valueを付け加えたところうまくいきました。

小僧さんに教えてもらったSQLも試してみました。

ありがとうございました。

一つだけ、どうしても分からないことがあるのですが、

一部、どんなに値を確認してみても、TypeNameも値も一緒なのに、値が違うというように認識されてしまうものがありました。

Dictionary でやってみても、SQLでやってみても、全く同じ結果になりました。

数字の箇所なんですが、
たとえば、新データ9.2 旧データ9.2 TypeName 両方ともDouble

私にはすべて同じように感じるのですが、原因があるとすれば、何が考えられるのでしょうか?

度々、すみません。

>▼KANA さん:
>こんにちは。
>
>>>      MyDic.Add "1", rs(0)
>>>      MyDic.Add "2", rs(0).Value
>>
>> 上記の部分で rs(0)とrs(0).value の意味が
>> いまいちわかりませんので教えていただけないでしょうか?
>
>ごめんなさい。
>KANAさんの記述を使うと
>
>Midic.Add "1", rs![F1]
>Midic.Add "2", rs![F1].Value
>
>の方が解りやすかったですね。
>
>rs(0) は rs の一番初めのフィールドを表しています。
>
>
>>rs(0)のほうはFieldとでてきてて
>
>rs![F1] をDictionary オブジェクトの Item 値に代入すると
>rs![F1] の値ではなく、ADODB.Recordset で定義されている
>フィールドオブジェクトへの参照を代入してしまっている事を意味します。
>
>初めに投稿されたコードですと、
>
>>>> rs.Close
>>>> Set rs = Nothing
>
>の箇所で rs への参照が切れてしまっている為、
>フィールドも参照できなくなりエラーが発生しております。
>
>値だけをDictionaryオブジェクトに入力するのであれば
>rs![F1].Value と明示的に指定しなければいけないという事です。
>
>
>KANAさんのコードをそのまま生かすとなると、
>
>>  MyVal = Array(rs![F1], rs![F2], rs![F3], rs![F4], rs![F5], rs![F6], rs![F7], _
>>        rs![F8], rs![F10], rs![F11], rs![F12], rs![F13], rs![F14], rs![F17])
>
>  MyVal = Array(rs![F1].Value, rs![F2].Value, rs![F3].Value, rs![F4].Value, rs![F5].Value, rs![F6].Value, rs![F7].Value, _
>        rs![F8].Value, rs![F10].Value, rs![F11].Value, rs![F12].Value, rs![F13].Value, rs![F14].Value, rs![F17].Value)
>
>となりますね。
>
>
>> Accessで、こういうことをやる場合は、
>> Dictionaryはあまり使わないほうがいいのでしょうか?
>
>当方でしたら、SQLで片づけてしまうかと思われます。
>提示されたコードのうち、左3つを比較するSQLでしたら
>
>SELECT
>  旧TBL.key
> , IIf([旧TBL]![F1]=[新TBL]![F2],"",[新TBL]![F2]) AS 比較1
> , IIf([旧TBL]![F2]=[新TBL]![F3],"",[新TBL]![F3]) AS 比較2
> , IIf([旧TBL]![F3]=[新TBL]![F4],"",[新TBL]![F4]) AS 比較3
>FROM
>  旧TBL
>INNER JOIN
>  新TBL
>ON 旧TBL.key = 新TBL.key
>WHERE NOT(
>     ([旧TBL]![F1]=[新TBL]![F2])
>   AND ([旧TBL]![F2]=[新TBL]![F3]) 
>   AND ([旧TBL]![F3]=[新TBL]![F4])
>         )
>
>
>上記のSQLをクエリのSQLビューに張り付け実行すると
>結果が出るかと思われます。
>(コピーペーストする際は
> 全角スペースは半角スペースに変換して下さい)
>
>ただ、自分に慣れている方法で結果を出すことは
>決して悪い事だと思いませんので
>まずはコードの問題を解決した後
>ご興味があればSQLにも挑戦されてみてはいかがでしょうか。

【12000】Re:二つのテーブルを比較する方法
発言  小僧  - 11/5/25(水) 12:12 -

引用なし
パスワード
   ▼KANA さん:
こんにちは。

> うまくいきました。

まずは結果が出まして何よりです。


> 数字の箇所なんですが、
> たとえば、新データ9.2 旧データ9.2 TypeName 両方ともDouble

当方の手元にデータがある訳ではないので
かなりあてずっぽうになってしまいますが、

フィールドやコントロールに表示する小数点以下桁数の定義について
h tp://office.microsoft.com/ja-jp/access-help/HP005248499.aspx

に書いてある通り、表示する桁数のみ変更する事が可能です。

小数1桁までを表示する様な設定になっていると、
実際のデータは 9.15 だったり 9.24 だったりしても
見た目は同じ 9.2に見える事になります。

まずはこの辺を疑ってみましょう。

【12001】Re:二つのテーブルを比較する方法
お礼  KANA  - 11/5/25(水) 17:22 -

引用なし
パスワード
   ▼小僧 さん:

なるほどです。
9.2の下桁にも数値があるのかもしれないということも
考えられるんですね。
もう一度データを確認してみます。
Accessをやるときは、いつも何かトラブルに見舞われ、
必死になってしまいます。

今回は、本当にありがとうございました。


>▼KANA さん:
>こんにちは。
>
>> うまくいきました。
>
>まずは結果が出まして何よりです。
>
>
>> 数字の箇所なんですが、
>> たとえば、新データ9.2 旧データ9.2 TypeName 両方ともDouble
>
>当方の手元にデータがある訳ではないので
>かなりあてずっぽうになってしまいますが、
>
>フィールドやコントロールに表示する小数点以下桁数の定義について
>h tp://office.microsoft.com/ja-jp/access-help/HP005248499.aspx
>
>に書いてある通り、表示する桁数のみ変更する事が可能です。
>
>小数1桁までを表示する様な設定になっていると、
>実際のデータは 9.15 だったり 9.24 だったりしても
>見た目は同じ 9.2に見える事になります。
>
>まずはこの辺を疑ってみましょう。

370 / 2272 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
1078193
(SS)C-BOARD v3.8 is Free