MS Project VBAの真髄:UniqueIDを鍵とした「依存関係」の高速構築術
現場のプロジェクトマネージャーがExcelで管理する数千行のWBS。これをMS Projectへインポートし、複雑な依存関係(Predecessors)を一瞬で組み上げる――。この自動化を「泥臭いループ処理」で実装しているようでは、プロのエンジニアとは呼べない。
今回は、MS Project VBAにおける「タスクの探索コスト」を極限まで削ぎ落とし、`Dictionary`オブジェクトを用いて、大規模プロジェクトでも一瞬で依存関係を解決する「プロの設計思想」を伝授する。
—
1. なぜ「タスク名検索」は罪なのか
初心者が最初に陥る罠が、`For Each`ループで全タスクを回し、「タスク名が一致したら…」という条件分岐を繰り返すことだ。
タスク数が増えれば増えるほど、計算量は指数関数的に増大する。さらに、プロジェクト現場では「同じタスク名」が重複することなど日常茶飯事だ。
「UniqueID」こそが唯一無二の正義である。
MS Projectにおいて、ユーザーが編集可能なID(ID)は行の挿入や削除で変動するが、`UniqueID`はシステム内部で一意に固定される。CSVデータとProjectを紐付ける際は、この`UniqueID`をキーとしてマッピングするのが鉄則だ。
—
2. アーキテクチャ設計:Dictionaryによる高速インデックス化
今回のロジックの要諦は、「一度だけ全タスクを走査して、メモリ上にマッピングテーブルを作る」ことにある。
1. `Scripting.Dictionary`オブジェクトを生成。
2. 全タスクの `UniqueID` をキーに、`Task`オブジェクトそのものを値(Item)として格納。
3. 依存関係の定義データ(CSVなど)を読み込み、即座に該当タスクを取得。
このアプローチにより、タスク検索は $O(N)$ ではなく $O(1)$ に短縮される。
—
3. 実装:プロダクションコード
以下のコードは、CSVから `[UniqueID], [PredecessorUniqueID]` という形式のデータを読み込み、依存関係を反映させるためのテンプレートだ。
Option Explicit
‘ 依存関係を設定するプロシージャ
Public Sub ApplyDependenciesFromCSV(filePath As String)
Dim proj As Project
Set proj = ActiveProject
‘ 1. タスクのインデックスを作成
Dim taskMap As Object
Set taskMap = CreateObject(“Scripting.Dictionary”)
Dim t As Task
For Each t In proj.Tasks
If Not t Is Nothing Then
‘ UniqueIDをキーにタスクオブジェクトを格納
taskMap.Add t.UniqueID, t
End If
Next t
‘ 2. CSVを解析して依存関係を反映
Dim fileNo As Integer: fileNo = FreeFile
Dim lineData As String
Dim parts() As String
Open filePath For Input As #fileNo
Do Until EOF(fileNo)
Line Input #fileNo, lineData
parts = Split(lineData, “,”)
‘ parts(0):対象タスクID, parts(1):先行タスクID
Dim targetID As Long: targetID = CLng(parts(0))
Dim predID As Long: predID = CLng(parts(1))
If taskMap.Exists(targetID) And taskMap.Exists(predID) Then
‘ Predecessors プロパティに先行タスクのUniqueIDを渡す
‘ 「UniqueID=値」という形式で指定するのがミソ
taskMap(targetID).Predecessors = “UniqueID=” & predID
End If
Loop
Close #fileNo
MsgBox “依存関係の構築が完了しました。”, vbInformation
End Sub
—
4. 現場で生き残るための「注意点」
循環参照の検知
CSVデータにミスがあり、タスクAがタスクBを待ち、タスクBがタスクAを待つような「循環参照」が含まれると、Projectはエラーを吐く。本番環境に投入する際は、`On Error Resume Next` で逃げるのではなく、`Err.Number` を捕捉して、どのタスクでエラーが起きたかをログに出力する堅牢なエラーハンドリングを実装すべきだ。
CSVのエンコード問題
Excelから出力したCSVは、しばしばShift-JISで保存される。VBAの `Input` 関数はこれに依存するため、文字コードが混在する環境では `ADODB.Stream` を使用してUTF-8を確実に読み込む実装に切り替えることを推奨する。
パフォーマンスの重み
タスク数が数万件を超える場合、`ScreenUpdating` を `False` にするだけでは不十分だ。計算モードを `pjManualCalculation` に切り替えてから処理を行い、最後に再計算(`CalculateAll`)を走らせることで、処理速度は劇的に向上する。
—
最後に:ツールは「道具」であれ
このロジックを理解したあなたには、ただ「動くコード」を書くのではなく、「プロジェクトの変更に耐えうるコード」を書いてほしい。
CSVのフォーマットが変わっても、マッピングのロジックさえ分離されていれば修正は最小限で済む。コードの保守性は、そのままあなたの業務の余裕に直結する。
技術は、苦労するためにあるのではない。楽をするために、そしてより本質的な価値(プロジェクトの成功そのもの)に時間を割くためにある。さあ、この知見をあなたのプロジェクトに実装してほしい。
