こんにちは!プロジェクト管理の現場で、日々スケジュール調整やリソース配分に頭を悩ませていませんか?
「あれ、このタスクとあのタスク、同じ人が同じ日に重複して割り当てられていないか……?」
「気づいたらスケジュールが矛盾していて、手戻りが発生した……」
MS Projectを使いこなす上で、こうしたデータの不整合(品質の低下)はプロジェクトを沈没させる隠れた爆弾です。Excelであれば目視や条件付き書式で何とかなることも、巨大なWBS(Work Breakdown Structure)を抱えるProjectの世界では、人力のチェックはほぼ不可能です。
今回は、マクロの記録から一歩抜け出し、「Project VBAを真に掌握する」ための第一歩として、タスクの重複を自動検知して警告を発する品質管理スクリプトを一緒に作っていきましょう。
ここをクリアすれば、Project VBAの基本構造やオブジェクトモデルはバッチリ見えてきますよ。温かく導きますので、リラックスしてついてきてくださいね。
—
1. Project VBAの心臓部:オブジェクトモデルを俯瞰する
Excel VBAとMS Project VBAの最大の違いは何だと思いますか?
それは、「タスクやリソースが持つ『時間(タイムライン)』と『依存関係』の重み」です。
Projectのオブジェクトモデルは、以下のような階層構造(ツリー構造)をしています。
Application (MS Project アプリケーション全体)
└─ Project (現在開いているプロジェクトファイル)
├─ Tasks (タスクのコレクション)
│ └─ Task (個々のタスク:開始日、終了日、名前など)
└─ Resources (リソースのコレクション)
└─ Resource (個々の人や機材)
Excelでいう「セル(Range)」を操作する感覚で `Task` を扱おうとすると、Project特有のスケジューリングエンジンの壁にぶつかります。例えば、タスクの日付を勝手に書き換えると、依存関係(先行タスク・後続タスク)によって他のタスクが連鎖的に動いてしまう。
だからこそ、「まずは現状のデータを正確に読み取り、判定し、警告する(ReadOnly的なアプローチ)」から始めるのが、実務で最も安全で確実なアプローチなのです。
—
2. 今回作成するスクリプトの仕様
実務で即座に使えるよう、以下の条件で「タスクの重複検知」を行います。
1. 対象スコープ: アクティブなプロジェクト内のすべての通常タスク(サマリータスクやマイルストーンを除外することも可能ですが、今回はシンプルに「開始日と名前が完全一致しているもの」を重複とみなします)。
2. 検知ロジック: 2重ループを回し、異なるタスクID間で「タスク名」と「開始日」が一致しているものをピックアップ。
3. アウトプット: 該当するタスクを見つけたら、イミディエイトウィンドウへのログ出力と、メッセージボックスによる警告を同時に行い、該当タスクのIDを通知する。
—
3. 実装コード:タスク重複検知・品質管理マクロ
それでは、開発環境(VBE:Visual Basic Editor)を開き、標準モジュールに以下のコードを貼り付けてみてください。
‘ ==============================================================================
‘ モジュール名: modTaskQualityControl
‘ 概要: プロジェクト内のタスク重複(名前と開始日)を検知し、品質管理を行う
‘ 執筆者: 首席VBAアーキテクト
‘ ==============================================================================
Sub CheckDuplicateTasks()
‘ 1. 変数の宣言(オブジェクト変数には必ず適切な型を指定します)
Dim tskTarget As Task
Dim tskCompare As Task
Dim duplicateCount As Long
Dim msgLog As String
‘ 初期化
duplicateCount = 0
msgLog = “【タスク重複検知レポート】” & vbCrLf & vbCrLf
‘ 2. アクティブなプロジェクトが存在するかチェック
If ActiveProject Is Nothing Then
MsgBox “現在開かれているプロジェクトがありません。”, vbCritical, “エラー”
Exit Sub
End If
‘ 3. プロジェクト内にタスクが存在するかチェック
If ActiveProject.Tasks.Count = 0 Then
MsgBox “チェック対象のタスクが存在しません。”, vbInformation, “通知”
Exit Sub
End If
‘ ステータスバーに進捗を表示(ユーザーへの親切心)
StatusBar = “タスクの重複チェックを実行中…”
‘ 4. 二重ループによる重複チェックの核心ロジック
‘ ※タスク数が数千件ある場合はパフォーマンスに配慮が必要ですが、基本構造として解説します。
For Each tskTarget In ActiveProject.Tasks
‘ サマリータスク(親タスク)や空行、削除済みタスクはスキップ
If Not tskTarget Is Nothing Then
If Not tskTarget.Summary And tskTarget.Name <> “” Then
For Each tskCompare In ActiveProject.Tasks
‘ 自分自身とは比較しない、かつ、サマリーや空行を除外
If Not tskCompare Is Nothing Then
If tskTarget.ID < tskCompare.ID And Not tskCompare.Summary And tskCompare.Name <> “” Then
‘ 条件判定:タスク名が完全一致 AND 開始日が完全一致
If tskTarget.Name = tskCompare.Name And tskTarget.Start = tskCompare.Start Then
duplicateCount = duplicateCount + 1
‘ ログメッセージの蓄積
msgLog = msgLog & “・重複検出 #” & duplicateCount & vbCrLf + _
” – タスクA: ID ” & tskTarget.ID & ” / 「” & tskTarget.Name & “」 (開始: ” & tskTarget.Start & “)” & vbCrLf & _
” – タスクB: ID ” & tskCompare.ID & ” / 「” & tskCompare.Name & “」 (開始: ” & tskCompare.Start & “)” & vbCrLf & vbCrLf
End If
End If
End If
Next tskCompare
End If
End If
Next tskTarget
‘ ステータスバーをリセット
StatusBar = “”
‘ 5. 結果の出力とユーザーへのフィードバック
If duplicateCount > 0 Then
‘ イミディエイトウィンドウにも詳細を出力(Ctrl + Gで確認可能)
Debug.Print msgLog
‘ 警告メッセージボックス
MsgBox “品質管理アラート: ” & duplicateCount & “件の重複タスクが検出されました。” & vbCrLf & _
“詳細はイミディエイトウィンドウ(Ctrl + G)を確認してください。”, _
vbExclamation, “データ品質チェック完了”
Else
MsgBox “素晴らしい!タスクの重複は検出されませんでした。データ品質は良好です。”, _
vbInformation, “データ品質チェック完了”
End If
End Sub
—
4. コードの深掘り解説:ここがプロの技
初心者のうちは、「動けばいいや」で書きがちですが、Project VBAならではの「罠」を避けるための重要なポイントがこのコードには詰まっています。
① `Not tskTarget Is Nothing` という鉄則
Excelの `Range` と違い、MS Projectの `Tasks` コレクションには、タスクが削除された跡地や空き番号が存在することがあります。そのため、`For Each` で回す際に `Nothing`(中身が空のオブジェクト)をそのままプロパティにアクセスしようとすると、容赦なく実行時エラー(ランタイムエラー)で落ちます。
これを防ぐためのガード節(Nullガード)が、オブジェクト操作におけるプロのたしなみです。
② `Summary` プロパティの除外
Projectでは、親タスク(子タスクを束ねるまとめのタスク)を「サマリータスク」と呼びます。サマリータスクの日付は子タスクの集計値として自動計算されるため、実態の作業を表すものではありません。重複チェックのノイズにならないよう、`If Not tskTarget.Summary` で綺麗に除外しています。
③ `tskTarget.ID < tskCompare.ID` による無駄な比較の排除
二重ループ(AとBを全件比較)を行う場合、単純に回すと「AとBの比較」のあとに「BとAの比較」もやってしまい、処理が2倍遅くなります。さらに同じ組み合わせを二重に検知してしまいます。
`ID` の大小関係でフィルターをかけることで、「一度比較したペアは二度とやらない」というスマートな最適化を行っています。
—
5. 現場で陥りやすいエラーと回避策
実際にこのマクロを運用に乗せるとき、以下の壁にぶつかることがあります。あらかじめ知っておきましょう。
- エラー: 「オブジェクト変数または With ブロック変数が見つかりません。」 (Error 91)
- 原因: 前述の `Nothing` チェックをサボっている証拠です。削除されたタスクIDにアクセスしようとしたときに発生します。コード内の `Not tskTarget Is Nothing` のガードを必ず確認してください。
- パフォーマンスの悩み: タスクが1万件を超えるとフリーズするように重い
- 原因: VBAの二重ループは、件数が多くなるとどうしても処理に時間がかかります。
- 対策: 実務で大規模プロジェクトを扱う場合は、ループに入る前に `Application.ScreenUpdating = False`(画面描画の停止)を入れる、あるいはタスクの配列(Array)に一度データを読み込んでメモリ上で高速処理するテクニック(高度なアーキテクチャ)が必要になります。今回は基礎編として標準的なオブジェクト走査をマスターしてください。
—
おわりに:品質管理を自動化するエンジニアへ
今回作成したスクリプトは、単なる「重複チェックマクロ」ではありません。
「属人化しがちなプロジェクトの健康状態を、コードの力で客観的に担保する」という、エンジニアリングの精神そのものです。
このスクリプトをベースに、「担当者(Resource Names)が同じなのに開始日が重複しているケース」などに条件をカスタマイズしていけば、あなただけの強力なプロジェクト監査ツールに進化させることができます。
ここをクリアしたあなたなら、もう「マクロの記録の奴隷」ではありません。自信を持って、次の自動化の扉を開いていきましょう!
