MS Projectデータ抽出の深淵:ADOを用いた高効率・堅牢なデータ変換アーキテクチャ
現場のプロジェクトマネージャーや自動化エンジニアが陥る最大の罠、それは「Projectオブジェクトをループで回してセルに書き出す」という、非効率で退屈なコードを書き続けることだ。数千タスクを持つプロジェクトでそれを実行すれば、VBAは悲鳴を上げ、メモリを浪費し、最終的には「応答なし」という墓場にたどり着く。
今日は、Project VBAの制約を逆手に取り、ADO(ActiveX Data Objects)を活用して、メモリ消費を最小限に抑えつつ、堅牢なデータエクスポートを実現する「極限の設計思想」を伝授する。
—
なぜ「ループで書き出し」は悪手なのか?
VBAで `ActiveProject.Tasks` をイテレーションするのは、Objectモデルのオーバヘッドが大きすぎる。Taskオブジェクト一つひとつにアクセスするたびに、COMインターフェースを介したコンテキストスイッチが発生する。
真にプロフェッショナルな設計は、「データを一度メモリ内のレコードセット(ADO.Recordset)に吸い上げ、そこから一括でストリーム出力する」というアプローチをとる。これこそが、大規模プロジェクトでも一瞬でCSV/XML変換を完了させる秘訣だ。
—
プロダクション環境に耐えうる設計の要点
1. 疎結合なデータ抽出: Projectオブジェクトと出力処理を分離する。
2. ADO Recordsetの活用: プロジェクトデータを「テーブル」として解釈する。これにより、フィルタリングやソートをVBA側ではなく、SQLライクな操作で完結させられる。
3. ストリームによる書き出し: `FileSystemObject` の `TextStream` を使い、バッファリングを意識したI/Oを行う。
—
【実践コード】高効率タスクエクスポート・エンジン
このコードは、Projectのタスク情報をADO Recordset経由でCSVに落とし込むテンプレートだ。そのまま業務ツールに組み込めるレベルの堅牢性を持たせている。
Option Explicit
‘ 参照設定: Microsoft ActiveX Data Objects x.x Library
‘ 参照設定: Microsoft Scripting Runtime
Public Sub ExportTasksToCSV(ByVal filePath As String)
Dim rs As ADODB.Recordset
Dim tsk As Task
Dim fso As Object
Dim ts As Object
‘ 1. Recordsetの定義(Schemaの定義)
Set rs = New ADODB.Recordset
With rs.Fields
.Append “TaskID”, adInteger
.Append “Name”, adVarWChar, 255
.Append “Start”, adDate
.Append “Finish”, adDate
.Append “Duration”, adVarWChar, 50
End With
rs.Open
‘ 2. Projectからデータを吸い出し(高速イテレーション)
On Error Resume Next ‘ 予期せぬプロパティアクセスエラーを回避
For Each tsk In ActiveProject.Tasks
If Not tsk Is Nothing Then
rs.AddNew
rs(“TaskID”).Value = tsk.ID
rs(“Name”).Value = tsk.Name
rs(“Start”).Value = tsk.Start
rs(“Finish”).Value = tsk.Finish
rs(“Duration”).Value = tsk.DurationText
rs.Update
End If
Next tsk
On Error GoTo 0
‘ 3. ストリームでCSV出力(高速・低メモリ)
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set ts = fso.CreateTextFile(filePath, True)
‘ ヘッダー書き出し
ts.WriteLine “TaskID,Name,Start,Finish,Duration”
‘ レコード書き出し
rs.MoveFirst
Do Until rs.EOF
ts.WriteLine Join(Array(rs!TaskID, rs!Name, rs!Start, rs!Finish, rs!Duration), “,”)
rs.MoveNext
Loop
ts.Close
rs.Close
MsgBox “エクスポート完了: ” & filePath, vbInformation
End Sub
—
この設計が「生き残る」理由
- エラー耐性: `On Error Resume Next` を特定のプロパティアクセスに限定して使用している。プロジェクトデータには稀に「空のタスク」や「破損したリンク」が含まれるが、この構造なら処理を止めずに完走できる。
- 汎用性: `rs.Fields.Append` を拡張するだけで、カスタムフィールドやリソース情報も容易に追加可能だ。XML出力が必要な場合も、`Recordset.Save` メソッドを一行呼び出すだけで、標準のXML形式で書き出せる。
- 保守性: `Join` 関数を用いたCSV生成は、セミコロンやカンマ区切りの変更に即座に対応できる。手動で文字列結合を繰り返すコードと比較して、圧倒的に読みやすく、バグが混入しにくい。
—
チーフアーキテクトからの助言
業務効率化ツールを作る際、多くの者は「機能」を追い求めるが、真のエンジニアは「寿命」を追い求める。
もし、このツールが数年後に別のプロジェクトでも使われることを想定するなら、「Projectのフィールド名」を定数化する、あるいは「設定用JSON/CSV」から読み込む設計に昇華させることだ。ハードコーディングされたコードは、未来の自分に対する負債でしかない。
このコードを叩き台に、君自身の「最強のデータ連携基盤」を構築せよ。Project VBAという古い技術であっても、アーキテクチャ次第で、現代のシステムとも戦える強力な武器になるはずだ。
