[[20220301104126]] 『Dictionaryオブジェクトの重複エラーについて』(まじっく) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『Dictionaryオブジェクトの重複エラーについて』(まじっく)

DictionaryオブジェクトのAddメソッドを実行した際に、以下のKeyの重複エラーが出てしまうのですが、原因がわからずに困っております。

実行時エラー’457′:
このキーは既にこのコレクションの要素に割り当てられています。

やりたいこと:KeyとItemを入力したリストファイルから、ADO接続でKeyとItemを取得してDictionaryに登録する。

リストファイルは以下のパスと内容でSheet1のワークシートに保存されているものとします。
"C:\list.xlsx"


  A  B
1 Key Item
2 AAA あああ
3 BBB いいい
4 CCC ううう
5 DDD えええ
6 EEE おおお

記述したコード:
参照設定:Microsoft ActiveX Data Objects 2.8 Library, Microsoft Scripting Runtime

Sub listからDictionaryに登録()

    Dim CN As New ADODB.Connection
    Dim RS As New ADODB.Recordset
    Dim SQL As String
    Dim Dic As New Dictionary

    With CN
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .Properties("Extended Properties") = "Excel 12.0;HDR=Yes"
        .Open "C:\list.xlsx"
    End With

    SQL = "SELECT * FROM [Sheet1$]"
    RS.Open SQL, CN, adOpenKeyset, adLockReadOnly
    Do Until RS.EOF
        'Debug.Print RS.Fields("Key") & " " & RS.Fields("Item")
        Dic.Add RS.Fields("Key"), RS.Fields("Item")
        RS.MoveNext
    Loop

    RS.Close
    Set RS = Nothing
    CN.Close
    Set CN = Nothing

End Sub


Dic.Add RS.Fields("Key"), RS.Fields("Item")の行で、エラーが出て止まってしまいますが、コメントアウトしているDebug.Printの行で確認すると、Keyは明らかに重複しているようには思えません。

原因がわかりましたら、ご教示いただけると幸いです。
よろしくお願いいたします。

< 使用 Excel:Excel2019、使用 OS:Windows10 >


Dic.Add RS.Fields("Key"), RS.Fields("Item")

Dic.Add RS.Fields("Key").Value, RS.Fields("Item").Value
に修正してください
.Value をつけないとFieldオブジェクトがkeyになるようですね

(とおりすがり) 2022/03/01(火) 11:04


詳細は知りませんが、
Dic.Add RS.Fields("Key").Value, RS.Fields("Item").Value
とすればよいのでは?

なお、キーが重複していると、その書き方ではエラーになりますよ。
事前に Existsを使った存在確認が必要です。
もしくは、下記の書き方ならエラーにならず上書きされます。
Dic(RS.Fields("Key").Value) = RS.Fields("Item").Value

#かぶりましたが、そのまま。
(γ) 2022/03/01(火) 11:14


とおりすがり様、γ様

解決いたしました!!

レコードの値の取得にvalueが必要という認識がなく、いままでやってきておりました。
大変勉強になりました。
ご教示いただきありがとうございました。
(まじっく) 2022/03/01(火) 11:21


 余談です。(関連性はあります)

 (1)
 よくある話で、似た話があります。

 Sub test2()
     Dim dic As Object
     Set dic = CreateObject("Scripting.Dictionary")
     For k = 2 To 3
         dic.Add Cells(k, 1), Cells(k, 2)
     Next
 End Sub
 を、下記のデータを使って動作させると、どうなると思いますか?
     A    B
 1  Key  Item
 2  AAA  あああ
 3  AAA  いいい

 AAAが重複しているので、エラーになる、と思いきや、エラーにはなりません。

 なぜなら、dictionaryに与えたキーは、
 値ではなく、Rangeオブジェクトなので、
 Addressなども違うし、同一ではないのでエラーにならず、
 結果として二つのキーを持った辞書ができてしまうわけです。
 また、dic("AAA")などとしても結果は返って来ないのです。

 したがって、この場合もきちんと.Value(または.Text)を付ける必要があります。
 これは比較的よく出てくる話ですね、というTipsのご紹介。

 (2)
 で、質問にあったケースで、
 Dic.Add RS.Fields("Key"), RS.Fields("Item")
 についても同じようにオブジェクトとして認識されるなら
 問題ないのではと、一見すると思います。

 しかし、最初に登録したkey,itemは、
 RS.MoveNext
 でカーソルを変えたときに、それに伴って動いてしまうわけです。
 そして、再度、
 Dic.Add RS.Fields("Key"), RS.Fields("Item")
 とやると、まさにキーが一致してしまって同じオブジェクトと判定されてしまうわけです。 

(γ) 2022/03/01(火) 12:24


γ様

Dictionaryを使う際に、セルから値を取得する時は.Valueをつけておりましたが、
ADOで取得したレコードの取り扱いに慣れていなかったもので、.Value を付ける認識がありませんでした。

おかげさまで、ループの2回目でエラーになった原因がよくわかりました。
追加コメントありがとうございました。

(まじっく) 2022/03/01(火) 12:49


すいません。
ちょっと変なことを言ってしまったようです。訂正です。ご返事は不要です。

RS.Fields("Key")にアクセスしたときに、
カーソルの位置によって返ってくる値は変わるものの、
もともとRS.Fields("Key")というインスタンスは一つしかないので、
普通に「重複してしまう」ということでよかったと思います。
(Range("A2")とRange("A3")は元々違うインスタンスでした。これはまた違う話。)

>カーソルを変えたときに、それに伴って動いてしまうわけです。
というのも変で、即時的に変わるのではなく、値を取りに行ったときに変わるものでした。

妙なことを申し上げて失礼しました。

(γ) 2022/03/01(火) 14:40


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.