【入門編】外部SQL ServerからWBS階層と依存関係データを取得し、Projectへ同期するデータ連携パイプライン – Project VBA解析バイブル

スポンサーリンク

こんにちは!プロジェクト管理の現場で、ExcelやMS Projectの自動化に頭を悩ませていませんか?

「マクロの記録」ボタンを押すだけの世界から一歩抜け出し、いよいよ外部のデータベース(SQL Server)とガッツリ連携させて、WBS(Work Breakdown Structure)や依存関係を自動構築する――。今回は、そんなエンタープライズレベルのProject VBAパイプラインの極意を伝授します。

「VBAでデータベース?難しそう…」と思うかもしれませんが、安心してください。一つひとつのオブジェクトのライフサイクルと、データの流れのツボさえ押さえれば、驚くほど堅牢で美しい自動化が手に入ります。

ここをクリアすれば、あなたも立派なProject VBAのアーキテクトです。さあ、一緒に深淵なる世界へ足を踏み入れましょう!

1. なぜ「SQL Server × MS Project」の自動連携なのか?

現場のプロジェクトマネージャーが最も嫌がる作業、それは「Excelや別システムで管理しているWBSの最新状態を、手動でMS Projectに転記し、数千行のタスクの先行・後続関係をポチポチと設定し直すこと」です。

これを手作業でやると、ヒューマンエラーの温床になり、変更が入るたびに絶望的な修正地獄が待っています。

だからこそ、「正義のデータソースであるSQL Server」から一気にデータを引き抜き、「MS ProjectのTaskオブジェクト群」へ一瞬で流し込むパイプラインをVBAで構築するのです。

全体アーキテクトの視点:データ連携の流儀

1. ADODBを使ってSQL Serverへ接続し、WBS階層と依存関係のフラットデータを取得する。
2. MS Project側の既存タスクを安全にクリア(または差分更新)する。
3. 取得したデータの「階層(アウトラインレベル)」を正しく再現しながら`Tasks.Add`で生成する。
4. 最後に「先行タスク(Predecessors)」の依存関係を配線する。

この順番を守るのが、Project VBAを制する鉄則です。

2. 実装の全体像:SQL Server同期パイプライン

それでは早速、実戦でそのまま使えるエンタープライズ・コードを公開しましょう。VBAの標準モジュールに貼り付けて実行できるように設計しています。

‘ ==============================================================================
‘ モジュール名: modProjectSyncPipeline
‘ 概要: SQL ServerからWBSと依存関係を取得し、MS Projectへ同期する
‘ ==============================================================================
Option Explicit

Public Sub SyncWBSFromSQLServer()
‘ 1. 変数の宣言 (ADOとProjectオブジェクト)
Dim conn As Object
Dim rs As Object
Dim connString As String
Dim query As String

Dim tsk As Task
Dim targetTask As Task
Dim predID As Long

‘ エラーハンドリングの準備
On Error GoTo ErrorHandler

‘ 2. ADODBコネクションの確立
‘ ※実際の環境に合わせて接続文字列(Server, Database, UID, PWD)を変更してください
connString = “Provider=SQLOLEDB;Server=YOUR_SERVER_NAME;Database=YOUR_DB_NAME;Uid=YOUR_USER;Pwd=YOUR_PASSWORD;”

Set conn = CreateObject(“ADODB.Connection”)
conn.CursorLocation = 3 ‘ adUseClient
conn.Open connString

‘ 3. WBSデータ取得クエリの実行
‘ アウトライン番号順、またはID順にソートして取得するのがポイントです
query = “SELECT TaskUID, TaskName, Duration, OutlineLevel, PredecessorUID FROM View_WBS_Export ORDER BY SortOrder”
Set rs = conn.Execute(query)

If rs.EOF Then
MsgBox “同期するタスクデータが存在しません。”, vbExclamation, “データなし”
GoTo Cleanup
End If
Application.ScreenUpdating = False

‘ 4. 既存タスクの全削除(全リフレッシュ方式の場合)
‘ ※実運用では差分更新が望ましいですが、今回はパイプラインの基本として全クリアを採用
Dim i As Long
For i = ActiveProject.Tasks.Count To 1 Step -1
If Not ActiveProject.Tasks(i) Is Nothing Then
ActiveProject.Tasks(i).Delete
End If
Next i

‘ 5. タスクの生成と階層構造(WBS)の構築
Do While Not rs.EOF
‘ タスクの追加
Set tsk = ActiveProject.Tasks.Add(rs.Fields(“TaskName”).Value)

‘ 期間の設定 (分単位で格納されている場合などを考慮。例として日数指定)
tsk.Duration = rs.Fields(“Duration”).Value 480 ‘ 1日 = 8時間 = 480分

‘ ユーザー定義フィールド等にSQL側のUIDを保持させておくと後で便利です
tsk.Text1 = CStr(rs.Fields(“TaskUID”).Value)

rs.MoveNext
Loop

‘ 6. アウトラインレベル(階層構造)の再適用
‘ ※一度全タスクを作った後、レベル(インデント)を調整します
rs.MoveFirst
i = 1
Do While Not rs.EOF
Set tsk = ActiveProject.Tasks(i)
Dim targetLevel As Integer
targetLevel = rs.Fields(“OutlineLevel”).Value

‘ 現在のレベルと目標レベルを比較してインデントを調整
Do While tsk.OutlineLevel < targetLevel tsk.OutlineIndent Loop Do While tsk.OutlineLevel > targetLevel
tsk.OutlineOutdent
Loop

i = i + 1
rs.MoveNext
Loop

‘ 7. 依存関係(前提条件)の結び付け
‘ ※すべてのタスクが生成された後に実行するのが依存関係構築の鉄則です
rs.MoveFirst
i = 1
Do While Not rs.EOF
If Not IsNull(rs.Fields(“PredecessorUID”).Value) Then
Dim predUID As String
predUID = CStr(rs.Fields(“PredecessorUID”).Value)

‘ UIDから対応するタスクオブジェクトを逆引き
Set tsk = FindTaskByCustomText1(predUID) ‘ ※ヘルパー関数
Set targetTask = ActiveProject.Tasks(i)

If Not tsk Is Nothing Then
‘ 先行タスクとして追加 (FS関係)
targetTask.Predecessors.Add Task:=tsk
End If
End If

i = i + 1
rs.MoveNext
Loop

Application.ScreenUpdating = True
MsgBox “SQL ServerからのWBS同期が正常に完了しました!”, vbInformation, “成功”
GoTo Cleanup

ErrorHandler:
Application.ScreenUpdating = True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”

Cleanup:
‘ オブジェクトの解放 (メモリリークを防ぐためのプロの作法)
On Error Resume Next
If Not rs Is Nothing Then
If rs.State = 1 Then rs.Close
Set rs = Nothing
End If
If Not conn Is Nothing Then
If conn.State = 1 Then conn.Close
Set conn = Nothing
End If
End Sub

‘ ==============================================================================
‘ ヘルパー関数: Text1に格納されたSQL側のUIDからMS ProjectのTaskオブジェクトを返す
‘ ==============================================================================
Private Function FindTaskByCustomText1(ByVal uid As String) As Task
Dim t As Task
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
If t.Text1 = uid Then
Set FindTaskByCustomText1 = t
Exit Function
End If
End If
Next t
Set FindTaskByCustomText1 = Nothing
End Function

3. ここがエンジニアの腕の見せ所!コードの深掘りとポイント

上記のコードには、単なる「動くコード」を超えた、実務で絶対にハマるポイントを回避するための知見が詰まっています。

① なぜ「タスク作成」と「依存関係の結び付け」を分けるのか?

初心者がやりがちなミスが、「タスクを1つ作って、その場でSQLから取得した先行タスクIDとリンクさせようとする」ことです。
これだと、まだデータベース上で後ろ側にいる(生成されていない)タスクを指そうとしてしまい、「オブジェクトが見つかりません(Run-time error)」の餌食になります。

> 黄金律: 「すべてのタスク(骨組み)をまず作り、階層を整えてから、最後に依存関係(神経系)を配線する」

この2パス(2段階)方式を守るだけで、エラーの9割は防げます。

② `Application.ScreenUpdating = False` の魔力

MS Projectは、タスクが1行追加されるたびに、ガントチャートの再描画やスケジュール(CPM:クリティカルパス法)の再計算を裏で必死に行います。
数千行のデータをループで流し込むときに画面描画を有効にしたままだと、PCがフリーズしたかのように遅くなります。
処理の最初に画面更新を止め、最後に一気に再開させることで、パフォーマンスが数十倍〜数百倍に跳ね上がります。

③ ADODBとオブジェクトのライフサイクル管理

VBAで外部DBを扱う際、`CreateObject(“ADODB.Connection”)` を使った遅延バインディング(Late Binding)を採用すると、参照設定のバージョン違いによるエラー(DLL Hell)を回避できます。
また、処理の最後には必ず `rs.Close` と `conn.Close` を行い、メモリ(リソース)を解放する。これがプロのコードの美しさです。

4. 陥りやすいエラーと現場の罠

現場でこのパイプラインを動かす際、よく遭遇するトラブルと対策をまとめておきます。

1. 循環参照エラー(Circular Dependency)

  • 症状: SQL側のデータで「タスクAの先行がタスクB、タスクBの先行がタスクA」になっている場合、Projectがリンク作成時にエラーを吐きます。
  • 対策: あらかじめSQL Server側(ビューやストアドプロシージャ)で、C#やSQLの共通テーブル式(CTE)を使って循環参照がないかバリデーションしておきましょう。

2. UIDの型ミスマッチ

  • 症状: SQL Server側が `UNIQUEIDENTIFIER` 型や `INT` 型であっても、Project側の `Text1` に格納・比較する際は必ず `CStr()` などで文字列に明示的キャストしてください。型が違うと `FindTaskByCustomText1` が空振りします。

5. おわりに

お疲れ様でした!ここまで理解できれば、単なるマクロの記録者ではなく、立派な「エンタープライズ・オートメーション・エンジニア」です。

外部の信頼できるデータベース(SQL Server)と、プロジェクト管理の要(MS Project)をVBAでシームレスに繋ぐパイプラインは、あなたのチームの生産性を劇的に向上させる強力な武器になります。

「ここをこう変えたらもっと高速化するのでは?」といった探究心を忘れず、ぜひご自身のプロジェクトへ導入してみてください。
あなたのVBAライフが、より知的でエキサイティングなものになることを応援しています!

タイトルとURLをコピーしました