【初心者向け】Predecessorsプロパティの文字列操作:Excelの先行タスクIDをProject形式に変換するコツ
開発プロジェクトの現場において、Excelで管理されたWBS(Work Breakdown Structure)をMicrosoft Projectへインポート、あるいはVBAで同期させるという要件は、実務で幾度となく直面する壁だ。
特に頭を悩ませるのが、タスク間の依存関係(先行タスク)の引き継ぎである。
Excel側では単に `1, 2, 3` や `4FS+2d` といったカンマ区切りの文字列で保持されている先行タスクIDを、Microsoft Projectの `Task.Predecessors` プロパティにそのまま放り込んでも、Projectは容赦なく「実行時エラー」を吐き捨てる。Projectが要求するフォーマットと、現場のExcelが持つデータの間には、厳然たる「言語の壁」が存在するからだ。
今回は、この文字列の不一致を完全になくし、大規模なWBSであっても一瞬で、かつ絶対にエラーを起こさない堅牢な先行タスク設定ロジックを伝授する。
—
なぜ素朴な代入コードは実務で破綻するのか?
多くの初学者がやりがちな実装を見てみよう。
‘ 【悪例】絶対に真似してはいけないナイーブなコード
Dim t As Task
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ Excelから取得した文字列をそのまま突っ込む
t.Predecessors = ws.Cells(t.ID, “E”).Value
End If
Next t
一見、動くように見えるかもしれない。しかし、このコードはプロダクション環境では使い物にならない。理由は以下の通りだ。
1. IDの相対性と絶対性の乖離: Excelの行番号(1行目、2行目…)と、Project内のタスクの `ID` は、サマリータスクの挿入やフィルタリングによって容易にズレる。
2. プロジェクト間の書式依存: Projectのオプション設定(言語環境や日付・依存関係のデフォルトタイプ)によって、文字列の解釈が変わる。
3. 空白や不正文字の混入: 現場のExcelデータは汚い。「1, 2, 3 」のようにスペースが入っているだけで、Projectは先行タスクを見失う。
プロの自動化エンジニアとして、データ揺れを完全に吸収し、タスクの「UniqueID(一意の識別子)」を軸にした堅牢なマッピング構造を構築しなければならない。
—
堅牢な文字列変換アルゴリズムの設計思想
Excelのカンマ区切り文字列(例:`”10, 15, 20FS+3d”`)を安全にProjectへ渡すためには、以下の3ステップを踏む。
1. トリムと分解: 文字列をカンマ (`,`) で分割し、それぞれの要素の前後の空白を完全に除去する。
2. IDの検証と変換: 分割された各要素の中に、終了-開始(FS)などのラグ情報が含まれているかをパースし、Projectが正しく解釈できる形に整形する。
3. 安全な代入: タスクの行番号(ID)ではなく、変更されない `UniqueID` をベースにリンクを構築する。
特に、Excel上の「何行目か」というタスク番号を、Project側のどのタスクオブジェクトに紐づけるかというマッピング辞書(あるいはコレクション)の設計が肝となる。
—
【コピペで使える】プロダクション品質のVBAコード
以下のコードは、Excelの特定列にある先行タスク文字列を読み込み、アクティブなMicrosoft Projectのタスク群へ安全に依存関係を設定するプロシージャだ。
Option Explicit
Sub ImportPredecessorsSafely()
‘—————————————————————-
‘ 目的: Excelの先行タスク文字列を安全にProject形式に変換し適用する
‘ 前提: Excelのシート名が “WBS” であり、A列にID、E列に先行タスク文字列がある想定
‘—————————————————————-
Dim xlApp As Object
Dim xlWb As Object
Dim xlWs As Object
‘ 実行中のExcelインスタンスからアクティブシートを取得する想定(早期/晩期バインディングは適宜変更)
On Error Resume Next
Set xlApp = GetObject(, “Excel.Application”)
If xlApp Is Nothing Then
MsgBox “Excelが起動していません。”, vbCritical, “連携エラー”
Exit Sub
End If
Set xlWs = xlApp.ActiveSheet
On Error GoTo 0
If xlWs Is Nothing Then
MsgBox “有効なExcelシートが選択されていません。”, vbCritical, “連携エラー”
Exit Sub
End If
Dim t As Task
Dim rowIdx As Long
Dim rawPreds As String
Dim predArray() As String
Dim i As Long
Dim singlePred As String
Dim targetTask As Task
‘ 画面描画を停止してパフォーマンスを極限まで高める
Application.ScreenUpdating = False
‘ エラーハンドリングの要
On Error GoTo ErrorHandler
cii = 0
‘ Projectの全タスクを走査
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ 対応するExcel上の行を特定(ここではProjectのIDがExcelの行番号と一致していると仮定)
‘ ※実務ではUniqueIDやタスク名でマッピングするDictionaryを使うべきです
rowIdx = t.ID
‘ ExcelのE列から先行タスク文字列を取得
rawPreds = Trim(xlWs.Cells(rowIdx, 5.Value & “”))
If rawPreds <> “” And rawPreds <> “0” Then
‘ 1. 一度既存の先行タスクをクリアしてクリーンな状態にする
‘ (必要に応じてコメントアウトしてください)
t.Predecessors = “”
‘ 2. カンマ区切りで分解
predArray = Split(rawPreds, “,”)
For i = LBound(predArray) To UBound(predArray)
singlePred = Trim(predArray(i))
If singlePred <> “” Then
‘ 3. ここで必要に応じた文字列置換・検証を行う
‘ 例: ユーザーが単に “5” と入れた場合、ProjectはこれをタスクID 5 と解釈する。
‘ ラグやリンク形式(SS, FF等)が含まれている場合はそのまま渡すことでProjectが解析する。
On Error Resume Next
‘ ProjectのLinkTasksメソッドまたはPredecessorsプロパティへの追記
‘ 安全性を高めるため、エラーが発生しても他のタスクの処理を止めない
t.Predecessors = t.Predecessors & IIf(t.Predecessors = “”, “”, “,”) & singlePred
If Err.Number <> 0 Then
Debug.Print “警告: タスク ID ” & t.ID & ” への先行タスク [” & singlePred & “] の設定に失敗しました。”
Err.Clear
End If
On Error GoTo ErrorHandler
End If
Next i
End If
End If
Next t
Application.ScreenUpdating = True
MsgBox “先行タスクの同期が正常に完了しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
—
現場でエンジニアが陥る「3つの罠」と回避策
実務でこのコードを組み込む際、以下の罠に必ず遭遇する。事前に防衛策を講じておこう。
1. タスクの削除・並び替えによる「IDのズレ」
先ほどのコードでは簡略化のために `t.ID` を行番号として使っているが、Project内でタスクが並び替えられた瞬間、このロジックは崩壊する。
- 対策: Excel側にも `UniqueID` 列を持たせ、VBAの `ActiveProject.Tasks.UniqueID(id)` を通じてオブジェクトを直接取得するように設計を昇華させること。
2. 無限ループや循環参照の発生
ユーザーが誤って「タスク1の先行にタスク2、タスク2の先行にタスク1」といった循環参照をExcelに記述した場合、Projectはリンク設定時に実行時エラーを吐くか、最悪の場合はファイルが破損する。
- 対策: 代入時の `On Error` トラップを必ず張り、不正な依存関係はログ(`Debug.Print`)に吐き出してスキップする耐障害性(フォールトトレランス)を持たせること。
3. パフォーマンスの劣化
数千行規模のWBSにおいて、`For Each` の中で毎回プロパティ書き込みを行うと、COM Interopのオーバーヘッドで処理が数分単位でフリーズする。
- 対策: 今回のコードのようにはじめに `Application.ScreenUpdating = False` をかけ、さらに不要な再計算やビューの更新を抑制することが、プロのエンジニアの作法である。
—
総括
先行タスクの文字列操作は、一見すると単なる `Split` 関数の応用に見える。しかし、Microsoft Projectという巨大なスケジューリングエンジンの内部構造と、現場の生々しいExcelデータの乖離を埋めるためには、「データの正規化」と「厳格なエラーハンドリング」が不可欠だ。
本記事で紹介した設計思想とコードをベースに、あなたのプロジェクト管理を「属人化した手作業」から「秒速の自動化」へとアップデートしてほしい。
