【VBAリファレンス】VBA練習問題解答練習問題29(ロット引き当て)解答

スポンサーリンク

VBAによるロット引き当てロジックの設計と実装

在庫管理システムにおいて、ロット引き当て(Lot Allocation)は最も重要かつ複雑な処理の一つです。特に、先入れ先出し(FIFO)の原則に基づき、複数の在庫レコードから必要な数量を効率的かつ正確に引き当てるロジックは、実務レベルのVBAスキルを測る試金石となります。本記事では、ロット引き当てのアルゴリズムをVBAでどのように実装するか、その詳細なステップを解説します。

ロット引き当ての基本アルゴリズム

ロット引き当ての核心は、「要求数量」が満たされるまで、「在庫レコード」を順番に消費していくプロセスです。この処理には、以下のステップが不可欠です。

1. 在庫データの取得とソート:引き当て順序(FIFOなら日付順など)に従い、在庫リストを並び替えます。
2. ループ処理:要求数量が0になるまで、在庫レコードを1行ずつ読み込みます。
3. 判定と計算:現在の在庫レコードの数量と、残りの要求数量を比較します。
4. 更新処理:引き当てた数量を在庫から減算し、引き当て結果(実績データ)を記録します。

この際、最も注意すべきは「部分引き当て」です。在庫レコードの数量が要求数量より少ない場合、そのレコードを全量消費し、残りの要求数量を次のレコードに持ち越す処理が必須となります。

詳細解説と実装のポイント

VBAでこのロジックを実装する際、パフォーマンスと保守性を考慮する必要があります。

まず、セルを直接操作するのではなく、配列(Array)を利用してメモリ上で計算を行うことを強く推奨します。大量の在庫データに対してセルへの書き込みを繰り返すと、処理速度が著しく低下するためです。また、引き当て結果を別シートや別テーブルに書き出す際も、一度配列に格納してから一括出力する手法が定石です。

データ構造としては、在庫マスター(商品コード、ロット番号、数量、期限)と、受注データ(受注番号、商品コード、要求数量)を分離して管理します。VBA内では、Dictionaryオブジェクトを利用して商品コードごとの在庫リストをグループ化しておくと、検索と引き当ての効率が飛躍的に向上します。

ロット引き当てのサンプルコード

以下に、FIFOに基づいた基本的なロット引き当てのサンプルコードを示します。このコードは、指定された商品に対して、古いロットから順に引き当てを行う設計です。

Sub ExecuteLotAllocation()
    Dim wsStock As Worksheet, wsOrder As Worksheet, wsResult As Worksheet
    Dim stockData As Variant, orderData As Variant
    Dim resultList As Collection
    Dim i As Long, j As Long
    Dim remainingQty As Long
    Dim currentStock As Long
    
    ' データ取得(範囲は適宜調整してください)
    Set wsStock = ThisWorkbook.Sheets("在庫")
    Set wsOrder = ThisWorkbook.Sheets("受注")
    stockData = wsStock.Range("A2:D100").Value
    orderData = wsOrder.Range("A2:C10").Value
    
    Set resultList = New Collection
    
    ' 受注ループ
    For i = 1 To UBound(orderData, 1)
        remainingQty = orderData(i, 3) ' 要求数量
        
        ' 在庫ループ
        For j = 1 To UBound(stockData, 1)
            ' 商品コードの一致判定
            If stockData(j, 1) = orderData(i, 2) And stockData(j, 3) > 0 Then
                currentStock = stockData(j, 3)
                
                ' 引き当て計算
                If currentStock >= remainingQty Then
                    ' 全量引き当て可能
                    resultList.Add Array(orderData(i, 1), stockData(j, 2), remainingQty)
                    stockData(j, 3) = currentStock - remainingQty
                    remainingQty = 0
                Else
                    ' 部分引き当て
                    resultList.Add Array(orderData(i, 1), stockData(j, 2), currentStock)
                    remainingQty = remainingQty - currentStock
                    stockData(j, 3) = 0
                End If
            End If
            
            ' 要求数量を満たせば終了
            If remainingQty <= 0 Then Exit For
        Next j
    Next i
    
    ' 結果の出力(簡易版)
    Call OutputResults(resultList)
End Sub

Sub OutputResults(res As Collection)
    Dim item As Variant
    Dim row As Long: row = 2
    With ThisWorkbook.Sheets("結果")
        For Each item In res
            .Cells(row, 1).Value = item(0)
            .Cells(row, 2).Value = item(1)
            .Cells(row, 3).Value = item(2)
            row = row + 1
        Next item
    End With
End Sub

実務アドバイス:エラーハンドリングと整合性の確保

実務の現場では、上記のような単純なロジックだけでは不十分です。以下の点に留意してください。

1. トランザクションの重要性:引き当て処理中にエラーが発生した場合、在庫データが不整合を起こす可能性があります。処理の最初と最後で在庫の整合性チェックを行うか、可能であればデータベース(SQL Serverなど)と連携したトランザクション制御を検討してください。
2. ロック制御:複数ユーザーが同時に在庫を引き当てる場合、排他制御が必要です。VBA単体では限界があるため、共有フォルダ上のファイルで運用する場合は、書き込み時の競合を避けるための工夫(排他フラグの設置など)が必須となります。
3. ログの保存:どの注文がどのロットを引き当てたのかという「引き当て履歴」は、後々のトレーサビリティ(追跡可能性)のために必ず残してください。実績テーブルを作成し、タイムスタンプと共に記録するのがプロの流儀です。
4. 警告メッセージの設計:引き当て可能な在庫が不足している場合、単にエラーを出すのではなく、不足している商品コードと数量を具体的にリストアップしてユーザーに提示するUIを設計しましょう。

まとめ

ロット引き当ては、単なるプログラミングの問題ではなく、ビジネスプロセスの設計そのものです。VBAでこの機能を実装する際は、コードの美しさだけでなく、「いかにしてデータの正確性を担保するか」「いかにして運用上のリスクを回避するか」という視点が欠かせません。

今回紹介したコードは、あくまで基礎的なアルゴリズムですが、これをベースにエラーハンドリングやログ記録、排他制御を組み込むことで、実務に耐えうる堅牢なシステムへと進化させることができます。まずはこのロジックを自身の環境で動かし、要求数量が在庫を超過した場合や、複数のロットをまたいで引き当てるケースなどをテストして、挙動を深く理解してください。

VBAエンジニアとしての価値は、複雑な業務要件をいかにシンプルでメンテナンス性の高いコードに落とし込めるかで決まります。この「ロット引き当て」という難題をクリアすることで、あなたのVBAスキルは確実に次のステージへと引き上げられるはずです。継続的な学習と改善を怠らず、現場の課題を解決し続けるエンジニアを目指してください。

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