エクセルVBAを使ってバラバラの経費精算書のデータをデータベースに集約するシリーズです。
前回はこちらの記事でした。
With文を使ってオブジェクトを省略する書き方について解説をしました。
さて、今回はエクセルVBAでWith文と組み合わせて他のワークブックを開く書き方についてお伝えしていきます。
では、行ってみましょう!
前回のおさらいと課題
前回のプログラムはこちらです。
Sub 経費精算データ取り込み()
Dim ws As Worksheet
Set ws = Workbooks("201807経費精算書_経費_3001.xlsx").Worksheets(1)
Dim month As Date: month = ws.Range("G4").Value
Dim departmentName As String: departmentName = ws.Range("G6").Value
Dim staffId As Long: staffId = ws.Range("G8").Value
Dim staffName As String: staffName = ws.Range("G7").Value
With ws
Dim i As Long: i = 12
Dim di As Long: di = 2
Do While ws.Cells(i, 1).Value <> ""
wsData.Cells(di, 1).Value = month '1 対象月
wsData.Cells(di, 2).Value = .Cells(i, 1).Value '2 日付
wsData.Cells(di, 3).Value = "" '3 部署No
wsData.Cells(di, 4).Value = departmentName '4 部署
wsData.Cells(di, 5).Value = staffId '5 社員No
wsData.Cells(di, 6).Value = staffName '6 氏名
wsData.Cells(di, 7).Value = .Cells(i, 2).Value '7 科目
wsData.Cells(di, 8).Value = .Cells(i, 5).Value '8 摘要
wsData.Cells(di, 9).Value = .Cells(i, 6).Value '9 金額
wsData.Cells(di, 10).Value = .Cells(i, 7).Value '10 備考
i = i + 1: di = di + 1
Loop
End With
End Sub
太郎さんの経費精算書ファイル「201807経費精算書_経費_3001.xlsx」の経費データを「経費データ」シートwsDataにコピー&ペーストをしていくというものです。
ファイルを開いていないと実行できない
ただ、このプログラム…太郎さんのファイルを開いた状態からでないと、以下のようなエラーが出てしまいます。
実行時エラー ‘9’: 「インデックスが有効範囲にありません」
…ちょっとよくわからないメッセージですね。
「デバッグ」ボタンをクリックすると、以下の部分でエラーが発生していることがわかります。
答えを言っちゃいますと、このエラーは、Workbooksコレクションの中に「201807経費精算書_経費_3001.xlsx」が存在していないことに起因しています。
そりゃそうです。ファイルを開いてないんですから。
今回はこの点を解消すべく、ファイルが閉じていてもプロシージャを実行できるように修正をしていきます。
Openメソッドで他のワークブックを開く
ファイルが閉じているのであれば、開いちゃえばいいんですね。
WorkbooksコレクションのOpenメソッドを使えばOKです。
つまり、冒頭に以下のような処理を入れてあげましょう。
Dim wb As Workbook
Set wb = Workbooks.Open(ThisWorkbook.Path & "\data\" & "201807経費精算書_経費_3001.xlsx")
Dim ws As Worksheet
Set ws = wb.Worksheets(1)
Openメソッドの使い方についてはこちらの記事をご参考ください。
ちなみに、太郎さんの経費精算書は、現在のマクロブックと同じ階層の「data」というフォルダの中にあるとします。
その際の、開くブックのフルパスの指定の仕方などは、以下の記事が参考になります。
ファイルを開いてデータを取り込むプロシージャ
以上をまとめたプロシージャがコチラです。
Sub 経費精算データ取り込み()
Dim wb As Workbook
Set wb = Workbooks.Open(ThisWorkbook.Path & "\data\" & "201807経費精算書_経費_3001.xlsx")
Dim ws As Worksheet
Set ws = wb.Worksheets(1)
Dim month As Date: month = ws.Range("G4").Value
Dim departmentName As String: departmentName = ws.Range("G6").Value
Dim staffId As Long: staffId = ws.Range("G8").Value
Dim staffName As String: staffName = ws.Range("G7").Value
With ws
Dim i As Long: i = 12
Dim di As Long: di = 2
Do While ws.Cells(i, 1).Value <> ""
wsData.Cells(di, 1).Value = month '1 対象月
wsData.Cells(di, 2).Value = .Cells(i, 1).Value '2 日付
wsData.Cells(di, 3).Value = "" '3 部署No
wsData.Cells(di, 4).Value = departmentName '4 部署
wsData.Cells(di, 5).Value = staffId '5 社員No
wsData.Cells(di, 6).Value = staffName '6 氏名
wsData.Cells(di, 7).Value = .Cells(i, 2).Value '7 科目
wsData.Cells(di, 8).Value = .Cells(i, 5).Value '8 摘要
wsData.Cells(di, 9).Value = .Cells(i, 6).Value '9 金額
wsData.Cells(di, 10).Value = .Cells(i, 7).Value '10 備考
i = i + 1: di = di + 1
Loop
End With
wb.Close
End Sub
開いたら閉じるべきなので、最後にCloseメソッドも入れています。
ワークブックを開いた上でWith
さて、以上で特に問題はないのですが、今回は一歩進んだOpenの仕方をしていきたいと思います。
以下のように、OpenメソッドとWith文と組み合わせるのです。
With Workbooks.Open(ThisWorkbook.Path & "\data\" & "201807経費精算書_経費_3001.xlsx")
With .Worksheets(1)
'処理
End With
.Close
End With
まず、1つ目のWith文により、開いたWorkbookオブジェクトを省略することができます。
少し難しい話ですが、Openメソッドの戻り値として開いたWorkbookオブジェクトを取得できますので、それをWith文のオブジェクトとして指定するわけですね。
そして、2つ目の「With .Worksheets(1)」で、その開いたワークブックの1枚目のWorksheetオブジェクトを省略できます。
つまり、2つ目以降のWithブロックでオブジェクトを省略した場合は、開いたワークブックの1枚目のシートを対象にした処理ということになります。
百聞は一見にしかず、今回のプログラムをこの書き方で記述してみますと、以下のようになります。
Sub 経費精算データ取り込み()
With Workbooks.Open(ThisWorkbook.Path & "\data\" & "201807経費精算書_経費_3001.xlsx")
With .Worksheets(1)
Dim month As Date: month = .Range("G4").Value
Dim departmentName As String: departmentName = .Range("G6").Value
Dim staffId As Long: staffId = .Range("G8").Value
Dim staffName As String: staffName = .Range("G7").Value
Dim i As Long: i = 12
Dim di As Long: di = 2
Do While .Cells(i, 1).Value <> ""
wsData.Cells(di, 1).Value = month '1 対象月
wsData.Cells(di, 2).Value = .Cells(i, 1).Value '2 日付
wsData.Cells(di, 3).Value = "" '3 部署No
wsData.Cells(di, 4).Value = departmentName '4 部署
wsData.Cells(di, 5).Value = staffId '5 社員No
wsData.Cells(di, 6).Value = staffName '6 氏名
wsData.Cells(di, 7).Value = .Cells(i, 2).Value '7 科目
wsData.Cells(di, 8).Value = .Cells(i, 5).Value '8 摘要
wsData.Cells(di, 9).Value = .Cells(i, 6).Value '9 金額
wsData.Cells(di, 10).Value = .Cells(i, 7).Value '10 備考
i = i + 1: di = di + 1
Loop
End With
.Close
End With
End Sub
かなりスッキリしていますよね。
開いたワークブックのシートをすぐに使いたいときにはWithとOpenを組み合わせると非常に簡潔にプログラムを書けるようになります。
ちなみに、お気づきかも知れませんが、ワークブックをオープンする書き方が「Workbooks.Open ファイル名」ではなくて「Workbooks.Open(ファイルのフルパス)」となっていることに注意してください。
メソッドの戻り値を使う場合はカッコが必要なのです。
まとめ
以上、エクセルVBAでWithをしながら他のワークブックを開く方法についてお伝えしました。
ワークブックを開くときはWithで開くことにより以降のオブジェクト名の表記を省略しスッキリ記述することができますし、開いたワークブック用のオブジェクト変数などを用意する必要もなくなります。
では、次回はVBAでフォルダを操作するためにFileSystemオブジェクトを使います。
どうぞお楽しみに!
連載目次:エクセルVBAで経費データをデータベースに集約する
請求書シリーズと逆のパターンですが、バラバラの帳票からデータ一覧つまりデータベースに情報を集めて蓄積していく、というお仕事も多いと思います。ここでは各担当者から提出された経費精算書をデータベースに蓄積するプログラムを目標にして進めていきます。- 【エクセルVBA入門】バラバラの経費精算書をデータにまとめる
- 【エクセルVBA入門】Do While~Loop文で条件を満たす間繰り返し
- 【エクセルVBA入門】繰り返しを使ってデータの転記をするときの2つのポイント
- 【エクセルVBA入門】With文でプログラムをスッキリわかりやすく書く
- 【エクセルVBA入門】他のワークブックをWithで開く&保存せずに閉じる
- 【エクセルVBA入門】フォルダやファイルを操作するFileSystemオブジェクトとその使い方
- 【エクセルVBA入門】For Each~Next文でフォルダ内のブック全てを開く方法
- 【エクセルVBA入門】シートのデータがある最終行番号を求めるステートメントを徹底解説
- 【エクセルVBA入門】開いたブック名から文字列を抽出して人為的なミスを回避する方法
- 【エクセルVBA入門】マクロを作るときに知っておきたいマスタデータのこと
- 【エクセルVBA入門】開いたブックのファイル名から番号を取り出して数値に変換する
- 【エクセルVBA入門】マクロでVlookupを使ってデータを検索する方法
- 【エクセルVBA入門】Vlookupメソッドを使ったときに発生するエラーを回避する方法
- 【エクセルVBA入門】エラーが発生したときに分岐処理を追加する方法
- 【エクセルVBA入門】オートフィルタや行の非表示で隠れている行を全て表示する