VB6.0だと、以下の構文でうまくいったんですが、
VB2005だとうまく動作しないようです。
どなたかご教授お願い致します。
Dim DB As DAO.Database
Dim RS As DAO.Recordset
Dim xlFileName As String
Dim xlSheetName As String
xlFileName = Form1.StatusBar1.Panels(12) & Dir(Form1.StatusBar1.Panels(12) & "ファイル名" & "*.xls")
xlSheetName = "シート名" & "$"
Set DB = OpenDatabase(xlFileName, False, False, "Excel 8.0;HDR=NO;IMEX=1")
Set RS = DB.OpenRecordset(xlSheetName)
文法の違いや、オブジェクト解放手順の差異などはありますが、
基本的な処理手順は同じであるはずです。
> VB2005だとうまく動作しないようです。
VB6 ではなく、2005 の方のコードを見せてください。
それが無いと、どこが間違っているのかを指摘できません。
(コードが正しいのに取得できないなら、I-ISAM ドライバの不足など、
「環境側の問題」を考慮せねばなりません)
ご指摘ありがとうございます!
VB2005だとこうなります。。
名前'OpenDatabase'は宣言されていません。というエラーになります。
Dim DB As DAO.Database
Dim RS As DAO.Recordset
Dim xlFileName As String
Dim xlSheetName As String
xlFileName = DataSheetPath & Dir(DataSheetPath & "NodeB-DataSheet" & "*.xls")
xlSheetName = "統合諸元" & "$"
DB = OpenDatabase(xlFileName, False, False, "Excel 8.0;HDR=NO;IMEX=1")
RS = DB.OpenRecordset(xlSheetName) 'Recordsetオブジェクトのオープン
すみません、こうでした。。
名前'OpenDatabase'は宣言されていません。というエラーになります。
Dim DB As DAO.Database
Dim RS As DAO.Recordset
Dim xlFileName As String
Dim xlSheetName As String
xlFileName = DataSheetPath & Dir(DataSheetPath & "ファイル名" & "*.xls")
xlSheetName = "シート名" & "$"
DB = OpenDatabase(xlFileName, False, False, "Excel 8.0;HDR=NO;IMEX=1")
RS = DB.OpenRecordset(xlSheetName) 'Recordsetオブジェクトのオープン
> 名前'OpenDatabase'は宣言されていません。というエラーになります。
こういう時は、「OpenDatabase が、どのオブジェクトのメソッドであるか」を
調べると解決しますよ。
DAO のヘルプやオブジェクトブラウザで確認すると、OpenRecordset が
DBEngine および Workspace のメンバである事を確認できるはずです。
DBEngine とは、DAO の最上位にあるオブジェクトなので、まずはそれを
Dim engine As New DAO.DBEngine()
として生成し、このオブジェクトから辿っていけば OK です。
本来であれば、(VB6でも)DBEngine オブジェクトを生成すべきなのですが、
DBEngine はグローバルオブジェクトになっているので、VB6 では
宣言を省略することができていたのです。
ということで、下記に具体例を示しておきます。
Marshal.ReleaseComObject による『オブジェクトの解放処理』も
書いてあるので、多少冗長なコードに見えるかもしれませんけれども。
'---------
Private ds As New DataSet()
Private table As DataTable
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
'DAO のオブジェクト生成
Dim engine As New dao.DBEngine()
Dim db As dao.Database = engine.OpenDatabase("C:\test.xls", False, False, "Excel 8.0;HDR=NO;IMEX=1")
Dim rs As dao.Recordset = db.OpenRecordset("Sheet1$")
'画面表示用の DataTable の準備
table = ds.Tables.Add("Sheet1")
Dim fs As dao.Fields = rs.Fields
Dim maxCount As Integer = fs.Count - 1
Dim f(maxCount) As dao.Field
For n As Integer = 0 To maxCount
f(n) = fs(n)
table.Columns.Add(f(n).Name)
Next
' Recordset から読み込んで、DataTable に格納
Do Until rs.EOF
Dim items As New ArrayList()
For n As Integer = 0 To maxCount
items.Add(f(n).Value)
Next
table.Rows.Add(items.ToArray())
rs.MoveNext()
Loop
'使い終わった DAO オブジェクトの解放
For n As Integer = 0 To maxCount
System.Runtime.InteropServices.Marshal.ReleaseComObject(f(n))
Next
System.Runtime.InteropServices.Marshal.ReleaseComObject(fs)
rs.Close()
System.Runtime.InteropServices.Marshal.ReleaseComObject(rs)
db.Close()
System.Runtime.InteropServices.Marshal.ReleaseComObject(db)
System.Runtime.InteropServices.Marshal.ReleaseComObject(engine)
'画面に表示
DataGridView1.DataSource = table
End Sub
ただし本当は、DAO に頼るよりも、ADO.NET (あるいはせめて ADO)による
データアクセスに移行すべきです。その方が解放処理も簡単ですし。
> ただし本当は、DAO に頼るよりも、ADO.NET (あるいはせめて ADO)による
> データアクセスに移行すべきです。その方が解放処理も簡単ですし。
ということで、ADO 版です。
DataAdapter によるサポートがあるので、DAO よりも扱いやすいかと。
Private ds As New DataSet()
Private table As DataTable
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Dim conStr As New OleDb.OleDbConnectionStringBuilder()
conStr.Provider = "Microsoft.JET.OLEDB.4.0"
conStr.DataSource = "C:\test.xls"
conStr("Extended Properties") = "Excel 8.0;HDR=NO;IMEX=1"
'ADO のオブジェクト生成
Dim rs As New ADODB.RecordsetClass()
rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient
rs.Open("Sheet1$", conStr.ConnectionString, , , ADODB.CommandTypeEnum.adCmdTableDirect)
'画面表示用の DataTable に読込
Using da As New OleDb.OleDbDataAdapter()
da.Fill(ds, rs, "Sheet1")
End Using
table = ds.Tables("Sheet1")
'使い終わった ADO オブジェクトの解放
If System.Runtime.InteropServices.Marshal.IsComObject(rs) Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(rs)
End If
'画面に表示
DataGridView1.DataSource = table
End Sub
最後に、ADO.NET 版。
COM オブジェクトの解放処理が不要になるので、これが一番楽かと。
Private ds As New DataSet()
Private table As DataTable
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Dim conStr As New OleDb.OleDbConnectionStringBuilder()
conStr.Provider = "Microsoft.JET.OLEDB.4.0"
conStr.DataSource = "C:\test.xls"
conStr("Extended Properties") = "Excel 8.0;HDR=NO;IMEX=1"
Dim sql As String = "SELECT * FROM [Sheet1$]"
Using da As New OleDb.OleDbDataAdapter(sql, conStr.ConnectionString)
da.Fill(ds, "Sheet1")
End Using
table = ds.Tables("Sheet1")
DataGridView1.DataSource = table
End Sub
>魔界の仮面弁士さん
ご説明ありがとうございました。
大変勉強になりました。
つきましては、言われるようにADO.NET 版へ移行しようかと
考えていますが、その場合エクセルのセル毎に値を取得
することは可能でしょうか?
因みにDAOでもうまく取得することができませんでした。
DAOで作成した構文は以下の通りです。
'DAO のオブジェクト生成
Dim engine As New DAO.DBEngine()
Dim db As DAO.Database = engine.OpenDatabase(xlFileName, False, False, "Excel 8.0;HDR=NO;IMEX=1")
Dim rs As DAO.Recordset = db.OpenRecordset(xlSheetName)
Do Until rs.EOF
With rs
変数=.Fields(0)
.MoveNext() '次のレコードに移動
End With
Loop
db.Close()
rs = Nothing
db = Nothing
> 考えていますが、その場合エクセルのセル毎に値を取得
> することは可能でしょうか?
指定する SQL コマンドに、
SELECT * FROM [Sheet1$B1:C3]
のような構文を使えば、「Sheet1 上の B1〜C3 セル範囲」になりますよ。
> 変数=.Fields(0)
これはマズイです。
DAO の「.Fields」は COM オブジェクトなので、「.Fields(0)」を
使う前に、.Fields を変数に受け、その変数から (0) を得るようにし、
最後に、その変数を「Marshal.ReleaseComObject」で解放せねばなりません。
(ADO.NET の場合は COM オブジェクトではないので、そうした手間は不要です)
http://support.microsoft.com/kb/317109/ja
http://support.microsoft.com/kb/321415/ja
先の私のサンプルでは、rs.Fields(0).Value の構文を使わず、わざわざ
rs.Fields を「dao.Fields 型の変数」fs に入れておき、そこからさらに、
fs(0) で得たオブジェクトを「dao.Field 型の変数」配列 f に受け、
最後に、それらのオブジェクトを「Marshal.ReleaseComObject」していますよね。
回答ありがとうございます。
DAOはかなり手間があるようなので、ADO.NET でやろうと思います。
ご教授頂いた構文で、DataGridViewにデータを反映するとこまでは
確認できたんですが、この値を変数に入れて、ピンポイントで
その値を参照することは可能でしょうか?
例えば、SELECT * FROM [Sheet1$B1:CC3000]だとその範囲全ての値ですが、
K列とAA列のみがほしいという場合。そして、そのK列の値を変数例えば、
変数(3000)とういう配列?に入れ、そこから参照するということは可能
でしょうか?
質問ばかりで申し訳ありませんが、宜しくお願い致します。
> K列とAA列のみがほしいという場合。
あとから、table.Columns.Remove するとか、
K 列だけ / AA 列だけの 2回にわけて取得するとか。
> そのK列の値を変数例えば、変数(3000)とういう配列?に入れ、そこから参照
ごめんなさい。質問の意味がわかりません。
質問の書き方が悪かったですね。すみません。。
> そのK列の値を変数例えば、変数(3000)とういう配列?に入れ、そこから参照
については、DataGridViewより参照する方法で回避できました。
最後に一つだけ質問させて下さい。
>K 列だけ / AA 列だけの 2回にわけて取得するとか。
ですが、2回に分けて取得し、DataGridViewには一回で反映する、ということでしょうか?
でしたら、2回に分けて取得する方法をご教授いただけますでしょうか?
> については、DataGridViewより参照する方法で回避できました。
DataGridView というか…。
DataTable に保存しているのですから、
value = table.Rows(行番号)(列番号)
で読み書きできますよ。
> でしたら、2回に分けて取得する方法をご教授いただけますでしょうか?
別々の DataTable に Fill すれば OK です。
一度、Excel から VB 側に取り込んでしまえば、
後はどうとでもマージできますよね。
なんとか求めているものができました!
色々お教え頂いて有難う御座いました。
ツイート | ![]() |