【テクニカル・上級編】外部データベース(SQL Server)からタスク情報を読み込む:ADOを用いたProject-DB連携の基礎 – Project VBA解析バイブル

スポンサーリンク

Project VBAを掌握する:SQL Server連携における「非同期」の幻想と「同期」の真髄

Project VBAを扱うことは、単なるマクロ記述ではない。それは、プロジェクトの「時間」という四次元のデータを、リレーショナル・データベースという静的な二次元構造にマッピングする重責を担うことだ。

多くのジュニアエンジニアがADO(ActiveX Data Objects)を用いてSQL Serverと対峙する際、接続文字列を貼り付けてレコードセットを回すだけのコードで満足する。だが、我々のようなアーキテクトにとって、それは「メモリリークへの招待状」に等しい。

今日は、Project VBAとSQL Serverを接続する際の「極限の知見」を共有する。

1. 接続の作法:コネクションプーリングを殺さないために

ADO接続において最大の罪は、コネクションの乱立だ。SQL Serverへの接続は高コストであり、`ADODB.Connection`オブジェクトを乱用すれば、接続プールは枯渇し、最終的にサーバー側で接続拒否が起きる。

接続のベストプラクティス

`Connection`オブジェクトは、モジュールレベルで保持し、アプリケーション終了まで使い回すのが鉄則だ。

‘ 接続文字列を定数化し、再利用性を確保する
Private Const CONN_STR As String = “Provider=SQLOLEDB;Data Source=SERVER_NAME;Initial Catalog=DB_NAME;Integrated Security=SSPI;”

Private m_cn As ADODB.Connection

Public Function GetConnection() As ADODB.Connection
If m_cn Is Nothing Then
Set m_cn = New ADODB.Connection
m_cn.ConnectionString = CONN_STR
m_cn.Open
ElseIf m_cn.State = adStateClosed Then
m_cn.Open
End If
Set GetConnection = m_cn
End Function

2. データ型マッピングの深淵:Projectの「独自仕様」を殺す

Projectのタスク(`Task`オブジェクト)をSQL Serverに投入する際、最も注意すべきは「Duration(期間)」と「Work(作業時間)」の単位の歪みだ。

  • Duration: Project内部では「分」単位の`Long`だが、表示上は「日」や「時間」に変換される。
  • Work: プロジェクト設定に依存する「分」単位の数値。

SQL Server側ではこれらを`FLOAT`または`BIGINT`で保持すべきだ。決して`NVARCHAR`で逃げてはならない。後続の集計クエリやBIツールでの可視化において、型変換(`CAST`)を強いるクエリはシステム全体のパフォーマンスを殺す。

3. メモリ解放の神学:伝説のアーキテクトは「Nothing」を信じない

VBAのガーベジコレクションは信用するな。特に`Recordset`や`Connection`のようなCOMオブジェクトは、明示的な解放が義務付けられている。

Public Sub SyncTaskToDB(ByVal t As Task)
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command

With cmd
Set .ActiveConnection = GetConnection()
.CommandText = “INSERT INTO Tasks (TaskUID, TaskName, Duration) VALUES (?, ?, ?)”
.Parameters.Append .CreateParameter(“@UID”, adGUID, adParamInput, , t.Guid)
.Parameters.Append .CreateParameter(“@Name”, adVarWChar, adParamInput, 255, t.Name)
.Parameters.Append .CreateParameter(“@Dur”, adDouble, adParamInput, , t.Duration / 60) ‘ 分を時間に変換
.Execute
End With

‘ ここからがプロの領域。オブジェクトの明示的破棄と参照のクリア
Set cmd = Nothing
‘ ※m_cnはモジュール終了時まで保持
End Sub

極限の知見: `Set obj = Nothing` を呼んだだけでは、循環参照やCOMインターフェースの解放が即時に行われない場合がある。システムが長期間起動し続けるような監視ツールを組む場合は、`Sleep`を挟む、あるいは`Win32 API`の`CoFreeUnusedLibraries`を呼び出すといった「泥臭い防衛策」が必要になる場面もあることを忘れるな。

4. レガシー環境における「同期の罠」

Projectのタスク数が増大(数千件超)した場合、単一スレッドでの同期はUIのフリーズを招く。しかし、VBAはシングルスレッドだ。

ここで取るべき戦略は「バッチ処理への転換」である。
1. タスクを`Collection`や`Scripting.Dictionary`にキャッシュする。
2. `Transaction`を使用し、一括でコミットする。
3. `Errors`コレクションを監視し、トランザクションのロールバックを制御する。

m_cn.BeginTrans
‘ ループ内でExecuteを実行
m_cn.CommitTrans

もしエラーが発生した場合は、`m_cn.RollbackTrans`を呼び出す。これを怠れば、部分的なデータのみがDBに残り、Projectファイルとの不整合という「システムの死」を招くことになる。

結びに:技術は「信頼」の上に成り立つ

システム間連携において、最も壊れやすいのはコードではなく「データ」だ。
Projectのタスクは常に変化する。その変化をSQL Serverという岩盤に刻み込む際、我々エンジニアがやるべきことは、単にデータを移動させることではない。

「予期せぬ中断が起きても、データの整合性が保たれる仕組み」を設計することだ。

VBAは古い。しかし、その老兵は今もなお、巨大なプロジェクトの心臓部を動かし続けている。諸君もまた、単なるコード書きではなく、データの番人たれ。

健闘を祈る。

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