• 締切済み

2次元のdictionary

こんにちは。 recordsetの結果をDictionaryにいれたいと思っています。 環境はWindows Vista、vbScriptで書いています。 set dc = createobject("scripting.dictionary") Set rs = Server.CreateObject("ADODB.Recordset") rs.open (sql文), con  for i = 0 to rs.recordcount -1 for j = 0 to rs.fields.count - 1 dc.add rs.fields(j).name, rs.fields(j).value next next ちょっとイメージっぽく書きましたが(このままではエラーでます)、要は複数のフィールドを持つ複数のレコードを入れられないかということです。 色々調べたりしてみたのですがわかりません。 できないのかな?と思いました。 もしできるなら書き方をご教授頂けたらと思います。 よろしくお願いします。

みんなの回答

  • end-u
  • ベストアンサー率79% (496/625)
回答No.8

>>dc(i) = rs.GetRows(1, adBookmarkCurrent) >これが理想なのですが、dc(i)という書き方はエラーになってしまいます。 >オブジェクトにindexがつけられればいいのですが。 "C:\temp\test.xls"のSheet1に適当な65535件のデータでテストしたコードを載せておきます。 特にエラーは出ないので、データもしくは環境のせいでしょうか。 >dc(i) = rs.GetRows(1, adBookmarkCurrent) とは、 dc.Add i, rs.GetRows(1, adBookmarkCurrent) と一緒で、i を index としています。 Const adBookmarkCurrent = 0 Const adOpenStatic = 3 Const wkName = "C:\temp\test.xls" Dim con Dim rs Dim sql Dim dc Dim i 'On Error Resume Next Set con = CreateObject("ADODB.Connection") With con   .Provider = "Microsoft.Jet.OLEDB.4.0"   .Properties("Extended Properties") = "Excel 8.0"   .Properties("Data Source") = wkName   .Open End With sql = "SELECT * FROM [Sheet1$]" Set rs = CreateObject("ADODB.Recordset") Set dc = CreateObject("scripting.dictionary") rs.Open sql, con, adOpenStatic Stop For i = 1 To rs.RecordCount   dc(i) = rs.GetRows(1, adBookmarkCurrent) Next rs.Close con.Close Stop MsgBox dc(1)(0, 0) & vbTab & dc(1)(1, 0) & vbTab & dc(1)(2, 0) MsgBox dc(2)(0, 0) & vbTab & dc(2)(1, 0) & vbTab & dc(2)(2, 0) MsgBox dc(dc.Count)(0, 0) & vbTab & dc(dc.Count)(1, 0) & vbTab & dc(dc.Count)(2, 0) Set dc = Nothing Set rs = Nothing Set con = Nothing If Err.Number <> 0 Then   MsgBox Err.Number & vbLf & Err.Description Else   MsgBox "end" End If #修正なしでVBAでも試せます。

  • rivoisu
  • ベストアンサー率36% (97/264)
回答No.7

いろいろ回答はあるけれど、結局どのようなデータを持ってどのように取り出すかがわからないとうろうろするばかりではないでしょうか。 私はキーを連結して1つのキーにしてしまえばと書いたけど 取り出すときに取り出すキーが二つともわかっていればこれでいいでしょう。 でも最初のキーで取り出したデータの中に2番目のキーがあるような場合はお手上げです。 正直連想配列の必要も無い場合もあるのではないかとも思っています。 どのようなデータを「どのように取り出したいか提示してもらえると回答も正解に塚づくのではないでしょうか、

  • end-u
  • ベストアンサー率79% (496/625)
回答No.6

Recordsetの結果をDictionaryに入れる時、何か別のkeyでレコード単位で入れるのですか? それともfields.Nameをkeyにしてフィールド単位で入れるのですか? GetRowsを使ってレコード単位で入れるなら Const adBookmarkCurrent = 0 Const adOpenStatic = 3 ': rs.Open sql, con, adOpenStatic Stop For i = 1 To rs.RecordCount   dc(i) = rs.GetRows(1, adBookmarkCurrent) Next rs.Close con.Close Stop MsgBox dc(1)(0, 0) & vbTab & dc(1)(1, 0) & vbTab & dc(1)(2, 0) MsgBox dc(2)(0, 0) & vbTab & dc(2)(1, 0) & vbTab & dc(2)(2, 0) こんな感じになるかと。 フィールド単位で、LoopでField別に配列を作ってもそんなに時間かかりますか? Dim v, w, x ': rs.Open sql, con Stop v = rs.GetRows ReDim w(UBound(v, 2)) For i = 0 To UBound(v, 1)   For j = 0 To UBound(v, 2)     w(j) = v(i, j)   Next   dc(rs.fields(i).Name) = w Next rs.Close con.Close Stop x = dc.keys MsgBox x(0) & vbTab & dc(x(0))(0) & vbTab & dc(x(0))(1) & vbTab & dc(x(0))(2) MsgBox x(1) & vbTab & dc(x(1))(0) & vbTab & dc(x(1))(1) & vbTab & dc(x(1))(2) Dictionaryに格納した後どうやって利用するかなのだと思いますが、 v = rs.GetRows ただ単に配列で保持しておくっていう意味じゃないんですよね?

harelip
質問者

補足

お返事ありがとうございます。 >dc(i) = rs.GetRows(1, adBookmarkCurrent) これが理想なのですが、dc(i)という書き方はエラーになってしまいます。 オブジェクトにindexがつけられればいいのですが。 >フィールド単位で、LoopでField別に配列を作ってもそんなに時間かかりますか? 処理件数によっては遅くなるのでは?という古い考えがありました; 経験言語の違う数名で話していたのですが、たとえばPHP経験者は連想配列で渡してもらいたい、他の者はオブジェクトで渡すべきだ(recordsetかDictionary)、などと色々意見がでまして。 私はVB経験者としてrecordsetかgetrowsでの配列渡しを提案したのですが、Rubyなどのように1行でできないか?と言われまして試行錯誤していました。 (つまり共通ライブラリの関数にsqlを渡すと接続・実行・切断を行って結果をもらいたい、と) recordsetはcloneが作れますが、さすがにコネクト切断すると中身も失われてしまいます。 格納後の処理の利便性ではなく、そういった経緯で悩んでいました。

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.5

#2&3です。 VBSでcollectionは使えないのですね、失礼しました。それでは、下記の様なのは如何でしょうか。安定して動くかどうかは定かでありません。珍奇な思いつきかも... Sub test3() Dim dic As Object, tempDic As Object Dim i As Long Set dic = CreateObject("Scripting.Dictionary") For i = 1 To 2 Set tempDic = CreateObject("Scripting.Dictionary") tempDic.Add "field_a", i tempDic.Add "field_b", "code" & Format(i, "00") dic.Add CStr(i), tempDic Set tempDic = Nothing Next i For i = 1 To 2 Debug.Print dic.Item(CStr(i)).Item("field_a") Debug.Print dic.Item(CStr(i)).Item("field_b") Next i End Sub #2が二次元配列で可能かどうかはお試し下さい。

  • imogasi
  • ベストアンサー率27% (4737/17070)
回答No.4

普通と違うやり方をしたいなら、この前に、何がしたいのか質問に書くべきでしょう。アイデアが横道にそれていませんか。 質問者の珍奇な思いつきに、つき合わされるのはかなわない。 他に普通のやり方があるのではないか。

harelip
質問者

補足

お返事ありがとうございます。 目的は、1つの関数でOpen Find Closeをしてデータを返せないか?というものです。 recordsetで返すと、その後別処理でCloseしないといけないので、 dc = Find(sql) みたいな感じで1行でできないかと思いました。

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.3

#2です。ちょっとピント外れでしたか。 下記の様なのは如何でしょうか。"a","b"のところをフィールド名にします。これなら、異なる型のフィールドのデータが入れられます。 Sub test2() Dim dic As Object Dim myKey As String Dim tempCollection As Collection Set dic = CreateObject("Scripting.Dictionary") Set tempCollection = New Collection myKey = "1" tempCollection.Add Item:=123, key:="a" tempCollection.Add Item:="ABC", key:="b" dic.Add myKey, tempCollection 'dictionaryにセット後、消してしまっても、dictionaryの中味は保持されている Set tempCollection = Nothing Debug.Print dic.Item(myKey)("a") Debug.Print dic.Item(myKey)("b") End Sub

harelip
質問者

お礼

お返事ありがとうございます。 Collectionを調べてみたのですが、VBScriptではCollectionが使えないようです;; 参考になりました。ありがとうございます!

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.2

dictionaryに配列を入れるコードをみたことがあります。 試しにやってみたら、下記の通りできました。VBAですが、ご参考まで。 Sub test() Dim dic As Object Dim myKey As String Dim i As Long Set dic = CreateObject("Scripting.Dictionary") myKey = "1" dic.Add myKey, Array(1, 2, 3, 4, 5) For i = 0 To UBound(dic.Item(myKey)) Debug.Print dic.Item(myKey)(i) Next i End Sub

harelip
質問者

補足

お返事ありがとうございます。 dic.Add myKey, Array(1, 2, 3, 4, 5) のArrayは1次元配列じゃないとやっぱりだめでしょうか? Getrowsを指定できれば使えるな~と思いました。 もし1次元配列で指定しなければいけないのなら、ループでField別に配列を作らないといけないので、処理時間をくってしまいそうなので、おとなしくrecordsetにしようと思います。

  • rivoisu
  • ベストアンサー率36% (97/264)
回答No.1

どのように取り出すのかが分かりませんが、二つのfieldを連結したものをキーにすれば一応連想配列はできると思います。

harelip
質問者

補足

お返事ありがとうございます。 >二つのfieldを連結したものをキー というのは具体的にはどういった手法なのでしょうか?

関連するQ&A