【入門編】外部データベース(SQL Server)からタスク情報を取得し、Projectへ同期する連携手法 – Project VBA解析バイブル

スポンサーリンク

こんにちは! プロジェクト管理の現場で、ExcelやProjectの操作に毎日のように頭を悩ませていませんか?

「外部のSQL Serverにある最新の進捗やタスクデータを、ワンクリックでMicrosoft Projectに反映させたい」
「WBSの階層構造や先行タスク(依存関係)まで、手動でポチポチ入力する地獄から抜け出したい」

そんな切実なエンジニアの叫びを解決するために、今日は私が培ってきた「Project VBAを極めるための実践知見」を余すところなくお伝えします。

マクロの記録が使えない孤高の巨人、Microsoft Project。その内部構造(オブジェクトライフサイクル)の癖を理解しさえすれば、外部データベースとの連携は驚くほど優雅に自動化できます。
ここをクリアすれば、あなたもProject VBAの基本はバッチリですよ! 一緒にマスターしていきましょう。

なぜSQL Server × Project連携でつまずくのか?

エンタープライズの現場では、タスクのマスターデータはSQL Serverなどのリレーショナルデータベースで管理され、現場のマネージャーはMicrosoft ProjectでWBSを引く、という分業体制が一般的です。

しかし、これを手動でやるとどうなるでしょう?

  • 何百行もあるタスクのインデント(階層)がズレる
  • 先行・後続タスクのIDが変わるたびに依存関係(Predecessors)が切れる
  • 進捗率の更新漏れが発生する

これをVBAで自動化する際、多くの人が「とりあえずレコードセットを上から順にProjectへ放り込む」という愚を犯します。
結果として何が起きるか? Project特有の「再計算コストの爆発」「存在しないタスクIDへの依存関係設定によるエラー(#Error)」の泥沼にハマるのです。

この泥沼を華麗に回避するための設計思想を、コードとともに見ていきましょう。

全体アーキテクチャ:3つのステップ

外部DBからタスク情報を取得してProjectへ同期するロジックは、以下の3ステップで組み立てます。

1. ADODBによるデータ抽出: SQL Serverからフラットなタスク一覧(WBS階層・依存関係含む)を取得する。
2. 一括削除またはスマートアップサート(更新・挿入): 既存のタスクをクリアし、親から順にタスクを再構築する。
3. 依存関係の結び直し: 全タスクが生成された後に、先行タスク(Predecessors)の配線を一網打尽に完了させる。

特に重要なのは「タスクの生成」と「依存関係の設定」を完全に分離するという点です。依存関係は、接続先のタスクがすでにProject上に存在していなければ結べないからです。

実装コード:SQL Server連携マクロ

それでは、現場でそのままコピペしてカスタマイズできる実用コードを公開します。
※あらかじめMicrosoft ProjectのVBAエディタ(`Alt + F11`)で、参照設定に 「Microsoft ActiveX Data Objects 6.1 Library」 を追加しておいてください。

Option Explicit

‘ ==============================================================================
‘ テーマ: SQL Serverからタスク情報を取得し、Projectへ同期・階層化する
‘ 著者: チーフアーキテクト
‘ ==============================================================================
Sub SyncTasksFromSQLServer()
Dim conn As Object
Dim rs As Object
Dim connStr As String
Dim sql As String

‘ 1. 接続文字列の定義(環境に合わせて変更してください)
connStr = “Provider=SQLOLEDB;Server=YOUR_SERVER_NAME;Database=YOUR_DB_NAME;Uid=YOUR_USER;Pwd=YOUR_PASSWORD;”

‘ 2. SQLクエリの定義(WBS順、階層順にソートして取得するのが鉄則です)
sql = “SELECT TaskName, Duration, WBSLevel, ParentWBS, PredecessorUID, WorkPercentComplete FROM M_Tasks ORDER BY SortOrder ASC”

‘ ADODBオブジェクトの生成
Set conn = CreateObject(“ADODB.Connection”)
Set rs = CreateObject(“ADODB.Recordset”)

On Error GoTo ErrorHandler

‘ データベース接続
conn.Open connStr
rs.Open sql, conn, 1, 1 ‘ adOpenKeyset, adLockReadOnly

If rs.EOF Then
MsgBox “同期すべきタスクデータが見つかりませんでした。”, vbExclamation
GoTo CleanUp
End If

‘ 3. Project側の既存タスクを一旦クリア(※実運用では差分更新を推奨しますが今回は新規構築ベース)
‘ 注意: アクティブプロジェクトのタスクを全削除します
Dim t As Task
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then t.Delete
Base Next t

‘ 計算モードを手動にしてパフォーマンスを爆上げする(超重要テクニック)
Application.Calculation = pjCalculationManual

Dim newTsk As Task
Dim rowIdx As Long
rowIdx = 1

‘ ==============================================================================
‘ フェーズ1: タスクの生成と名前・期間・進捗率・階層(インデント)の設定
‘ ==============================================================================
Do While Not rs.EOF
‘ タスクの追加
Set newTsk = ActiveProject.Tasks.Add(rs.Fields(“TaskName”).Value)

‘ 期間の設定(日単位など。必要に応じて変換)
newTsk.Duration = rs.Fields(“Duration”).Value & “d”

‘ 進捗率の設定
newTsk.PercentageComplete = rs.Fields(“WorkPercentComplete”).Value

‘ WBS階層(インデント)の調整
‘ データベース側で保持しているWBSレベルに応じてインデントを深くする
Dim targetLevel As Integer
targetLevel = rs.Fields(“WBSLevel”).Value

‘ 現在のタスクレベルを目標レベルまで合わせ込む
Do While newTsk.OutlineLevel < targetLevel newTsk.OutlineIndent Loop Do While newTsk.OutlineLevel > targetLevel
newTsk.OutlineOutdent
Loop

‘ 一時的にDBの行番号をユニークID代わりのテキストフィールドに保持しておく(後続の依存関係紐付けのため)
newTsk.Text1 = rs.Fields(“PredecessorUID”).Value
newTsk.Text2 = CStr(rowIdx) ‘ 自行のIDトラッキング用

rowIdx = rowIdx + 1
rs.MoveNext
Loop

‘ ==============================================================================
‘ フェーズ2: 依存関係(先行タスク)の配線
‘ ==============================================================================
‘ 全タスクが生成されたあとなので、どのIDを指している依存関係も安全に解決できます
Dim predTarget As String
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
predTarget = t.Text1 ‘ 先行タスクとして紐付けるべきDB側のIDや条件が入っている

If Trim(predTarget) <> “” And predTarget <> “0” Then
‘ 先行タスクの設定(例: “3FS” や タスクID指定)
‘ ProjectのLinkTasksメソッドやPredecessorsプロパティを利用
Call SetPredecessorByCustomID(t, predTarget)
End If
End If
Next t

CleanUp:
‘ 4. オブジェクトのクリーンアップと計算モードの復元
Application.Calculation = pjCalculationAutomatic

If Not rs Is Nothing Then
If rs.State Then rs.Close
End If
If Not conn Is Nothing Then
If conn.State Then conn.Close
End If

Set rs = Nothing
Set conn = Nothing

MsgBox “SQL Serverからのタスク同期が正常に完了しました!”, vbInformation
Exit Sub

ErrorHandler:
Application.Calculation = pjCalculationAutomatic
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub

‘ 補助プロシージャ: カスタムIDを元に先行タスクを探索して結ぶ
Private Sub SetPredecessorByCustomID(ByRef currentTask As Task, ByVal targetCustomID As String)
Dim searchTsk As Task
For Each searchTsk In ActiveProject.Tasks
If Not searchTsk Is Nothing Then
‘ Text2に保持している行IDと一致するかチェック
If searchTsk.Text2 = targetCustomID Then
‘ 先行タスクリンクを追加 (例: 終了-開始関係)
currentTask.Predecessors = searchTsk.ID & “FS”
Exit For
End If
End If
Next searchTsk
End Sub

ここで差がつく! プロジェクト自動化の極意(エンジニアの知見)

上記のコードには、単なる「動くコード」を超えた、現場で生き残るための知見が詰まっています。

1. `Application.Calculation = pjCalculationManual` の魔術

Microsoft Projectは、タスクを1行追加するたびに、全体のスケジュール、クリティカルパス、サマリータスクの日付を自動再計算します。これを数百行繰り返すと、VBAの実行スピードが何十倍も遅くなります。
処理の最初に手動モード(Manual)へ切り替え、最後に自動モード(Automatic)に戻す。これだけで、一瞬で処理が終わる爽快感を味わえます。

2. インデントの「相対制御」

WBSの階層を構築するとき、単純に「何回インデントするか」をDBから直接突っ込もうとすると、親がいない状態で子供をインデントしてしまい、Projectがエラーを吐くか、意図しないガタガタの構造になります。
コード内で行っているように、現在のレベル(`newTsk.OutlineLevel`)を監視しながら、ループで安全にインデント(`OutlineIndent`)とアウトデント(`OutlineOutdent`)を調律するのが、ロバストな(壊れにくい)プログラムの極意です。

3. 一時フィールド(Text1, Text2)の活用

データベース上の主キーや外部キーの関係性を、そのままProjectの標準ID(Task.ID)にマッピングしようとすると、タスクの並び順が変わった瞬間に破綻します。
一度 `Text1` や `Text2` といったユーザー定義テキストフィールドに一時的なIDを退避させ、「全タスクの生成が終わった後に、二度目のループで依存関係を結ぶ」。この二段階アプローチをとることで、複雑な依存関係も完璧に再現できます。

よくあるエラーと対策

  • 「実行時エラー ‘1100’: そのような先行タスクはありません」
  • 原因: 存在しないタスクIDを先行タスクに指定しようとしています。
  • 対策: 依存関係を結ぶループの前に、すべてのタスクが正しく生成されているか、また先行タスクのIDが存在するかを `If` 文でガードしてください。
  • 日本語やデータが文字化けする
  • 原因: ADODBの接続文字列でドライバーが古い(例: `Provider=Microsoft.Jet.OLEDB.4.0` など)か、文字コードのミスマッチ。
  • 対策: SQL Serverへの接続には `MSOLEDBSQL` または最新の `ODBC Driver` を使用し、接続文字列を適切に設定してください。

おわりに

いかがでしたでしょうか?
外部データベースとMicrosoft ProjectをVBAで繋ぎ込むアプローチは、一見すると難しく見えますが、「パフォーマンスへの配慮」「構造構築と依存関係設定の分離」という鉄則さえ守れば、あなたのプロジェクト管理業務を劇的に効率化する最強の武器になります。

「手作業の苦行からエンジニアリングの解放へ」。
ぜひ、あなたの現場でもこの知見を取り入れて、スマートな自動化を実現してくださいね。それでは、また次のアーキテクチャでお会いしましょう!

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