Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


2132 / 13645 ツリー ←次へ | 前へ→

【69761】材料費の内訳作成 さとちゃん 11/8/26(金) 21:25 質問[未読]
【69768】Re:材料費の内訳作成 UO3 11/8/27(土) 19:28 回答[未読]
【69770】Re:材料費の内訳作成 UO3 11/8/27(土) 21:53 発言[未読]
【69771】Re:材料費の内訳作成 UO3 11/8/27(土) 22:57 回答[未読]
【69773】Re:材料費の内訳作成 さとちゃん 11/8/28(日) 6:36 お礼[未読]

【69761】材料費の内訳作成
質問  さとちゃん  - 11/8/26(金) 21:25 -

引用なし
パスワード
   VBA初心者です。
職場で以下の材料費内訳表が必要です。類似サンプルを探しましたが見つからず、自力ではどうにもできないので良い方法があれば教えてください。よろしくお願いします。

購入部品一覧と使用部品一覧があり、同じ部品番号を複数の注文番号で購入しています。また、使用部品一覧では異なる号機で同じ部品を使用しています。使用部品一覧をベースに購入数を購入部品一覧から振り分ける作業を行い、材料費内訳表を作成したいのです。使用数に対し、購入数の方が多ければその数量を、不足であればマイナスを余剰欄へ表示。同じ部品番号であれば、注文番号は順不同です。
実際のデータは号機は10種、部品の種類は1000種ほど、使用部品一覧は4000行ほどあり、手作業で一週間かけて行っています。

sheet1(購入部品一覧)

   A      B    C
1 部品番号  注文番号 購入数
2 0101aaa  A0001   10
3 0101aaa  A0002   10
4 0101aaa  A0003   10
5 0202bbb  A0004    5
6 0202bbb  A0005   15

sheet2(使用部品一覧)

  A    B     C 
1 号機 部品番号 使用数
2  1  0101aaa  7
3  2  0101aaa  14
4  3  0101aaa  9
5  1  0202bbb  3
6  2  0202bbb  2
7  3  0202bbb  10

sheet3(材料費内訳表)

   A    B    C    D    E    F
1 号機 部品番号 使用数 注文番号 購入数 余剰
2  1  0101aaa   7   A001   7  
3  2  0101aaa  14   A001   3
4  2  0101aaa      A002   10
5  2  0101aaa      A003   1 
6  3  0101aaa   9   A003   9
7  1  0202bbb   3   A004   3
8  2  0202bbb   2   A004   2  
9  3  0202bbb  10   A005   10   5

【69768】Re:材料費の内訳作成
回答  UO3  - 11/8/27(土) 19:28 -

引用なし
パスワード
   ▼さとちゃん さん:

本件、コードというより、業務仕様というかビジネスロジックのおおげさにいえばアルゴリズムを
どのようにするかというテーマだろうと思いますし、その場合、目的によっては、このシートレイアウトでいいのかどうかも
掘り下げていく余地はあるのかなとも思いますが、それはさておき、一例です。
(要件を誤解している可能性もあります。まずはお試しください)

Option Explicit

Type Alloc
  PO As String
  used As Long
  flag As Boolean
End Type

Dim dic購入 As Object

Sub Sample()
  Dim dic合計 As Object
  Dim dic生産 As Object
  Dim c As Range
  Dim i As Long
  Dim key部品 As Variant
  Dim key号機 As Variant
  Dim key注文 As Variant
  Dim qty As Long
  Dim orgqty As Long
  Dim order As String
  Dim parts As String
  Dim machine As String
  Dim myAlloc As Alloc
  Dim first As Boolean
  Dim allocated As Long
  Dim remainder As Long
  
  Application.ScreenUpdating = False
  
  Set dic合計 = CreateObject("Scripting.Dictionary")
  Set dic購入 = CreateObject("Scripting.Dictionary")
  Set dic生産 = CreateObject("Scripting.Dictionary")
  
  With Sheets("Sheet1")
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
      parts = c.Value
      qty = c.Offset(, 2).Value
      order = c.Offset(, 1).Value
      dic合計(parts) = dic合計(parts) + qty
      If Not dic購入.exists(parts) Then Set dic購入(parts) = CreateObject("Scripting.Dictionary")
      dic購入(parts)(order) = qty
    Next
  End With
  
  With Sheets("Sheet2")
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
      parts = c.Offset(, 1).Value
      qty = c.Offset(, 2).Value
      machine = c.Value
      If Not dic生産.exists(parts) Then Set dic生産(parts) = CreateObject("Scripting.Dictionary")
      dic生産(parts)(machine) = qty
    Next
  End With
  
  With Sheets("Sheet3")
    .Cells.ClearContents
    .Range("A1:F1").Value = Array("号機", "部品番号", "使用数", "注文番号", "購入数", "余剰")
    i = 1
    For Each key部品 In dic生産
      allocated = 0
      For Each key号機 In dic生産(key部品)
        first = True
        qty = dic生産(key部品)(key号機)
        orgqty = qty
        Do
          i = i + 1
          .Cells(i, "A").Value = key号機
          .Cells(i, "B").Value = key部品
          If first Then .Cells(i, "C").Value = qty
          myAlloc = getQty(key部品, qty)
          .Cells(i, "D").Value = myAlloc.PO
          .Cells(i, "E").Value = myAlloc.used
          allocated = allocated + myAlloc.used
          qty = qty - myAlloc.used
          first = False
        Loop While myAlloc.flag And qty > 0
      Next
      remainder = dic合計(key部品) - allocated
      If remainder <> 0 Then .Cells(i, "F").Value = remainder
    Next
  End With
  
  dic生産.RemoveAll
  dic購入.RemoveAll
  Set dic生産 = Nothing
  Set dic購入 = Nothing
  Set dic合計 = Nothing
  
  Application.ScreenUpdating = True
  
  MsgBox "処理が終了しました"
  
End Sub

Private Function getQty(parts As Variant, qty As Long) As Alloc
  Dim ord As Variant
  Dim blc As Long
  
  If dic購入(parts).Count = 0 Then Exit Function
  
  For Each ord In dic購入(parts)
    blc = dic購入(parts)(ord)
    If blc >= qty Then
      getQty.used = qty
      dic購入(parts)(ord) = blc - qty
    Else
      getQty.used = blc
      dic購入(parts)(ord) = 0
    End If
    getQty.PO = ord
    getQty.flag = True
    If dic購入(parts)(ord) = 0 Then
      dic購入(parts).Remove (ord)
    End If
    Exit For
  Next
  
End Function

【69770】Re:材料費の内訳作成
発言  UO3  - 11/8/27(土) 21:53 -

引用なし
パスワード
   ▼さとちゃん さん:

ごめんなさい。
アップしたコード、材料不足くしたケースでは、うまく作表されません。
デバッグします。
とりあえず、材料が充分ある状態でお試しください。

【69771】Re:材料費の内訳作成
回答  UO3  - 11/8/27(土) 22:57 -

引用なし
パスワード
   ▼さとちゃん さん:

一応バグをつぶしたつもりです。
Dictionaryの「嵐?」になりましたが。

Option Explicit

Type Alloc
  PO As String
  used As Long
  flag As Boolean
End Type

Dim dic購入 As Object

Sub Sample()
  Dim dic使用 As Object
  Dim dic注文 As Object
  Dim dic生産 As Object
  Dim c As Range
  Dim i As Long
  Dim key部品 As Variant
  Dim key号機 As Variant
  Dim key注文 As Variant
  Dim qty As Long
  Dim orgqty As Long
  Dim order As String
  Dim parts As String
  Dim machine As String
  Dim myAlloc As Alloc
  Dim first As Boolean
  
  Application.ScreenUpdating = False
  
  Set dic使用 = CreateObject("Scripting.Dictionary")
  Set dic注文 = CreateObject("Scripting.Dictionary")
  Set dic購入 = CreateObject("Scripting.Dictionary")
  Set dic生産 = CreateObject("Scripting.Dictionary")
  
  With Sheets("Sheet1")
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
      parts = c.Value
      qty = c.Offset(, 2).Value
      order = c.Offset(, 1).Value
      If Not dic購入.exists(parts) Then Set dic購入(parts) = CreateObject("Scripting.Dictionary")
      dic購入(parts)(order) = qty
      dic注文(parts) = dic注文(parts) + qty
    Next
  End With
  
  With Sheets("Sheet2")
    For Each c In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
      parts = c.Offset(, 1).Value
      qty = c.Offset(, 2).Value
      machine = c.Value
      If Not dic生産.exists(parts) Then Set dic生産(parts) = CreateObject("Scripting.Dictionary")
      dic生産(parts)(machine) = qty
      dic使用(parts) = dic使用(parts) + qty
    Next
  End With
  
  With Sheets("Sheet3")
    .Cells.ClearContents
    .Range("A1:F1").Value = Array("号機", "部品番号", "使用数", "注文番号", "購入数", "余剰")
    i = 1
    For Each key部品 In dic生産
      For Each key号機 In dic生産(key部品)
        first = True
        qty = dic生産(key部品)(key号機)
        orgqty = qty
        Do
          i = i + 1
          .Cells(i, "A").Value = key号機
          .Cells(i, "B").Value = key部品
          If first Then .Cells(i, "C").Value = qty
          myAlloc = getQty(key部品, qty)
          .Cells(i, "D").Value = myAlloc.PO
          .Cells(i, "E").Value = myAlloc.used
          qty = qty - myAlloc.used
          first = False
        Loop While myAlloc.flag And qty > 0
      Next
      If dic注文(key部品) - dic使用(key部品) <> 0 Then _
              .Cells(i, "F").Value = dic注文(key部品) - dic使用(key部品)
    Next
  End With
  
  dic生産.RemoveAll
  dic購入.RemoveAll
  Set dic生産 = Nothing
  Set dic購入 = Nothing
  Set dic使用 = Nothing
  Set dic注文 = Nothing
  
  Application.ScreenUpdating = True
  
  MsgBox "処理が終了しました"
  
End Sub

Private Function getQty(parts As Variant, qty As Long) As Alloc
  Dim ord As Variant
  Dim blc As Long
  
  If dic購入(parts).Count = 0 Then Exit Function
  
  For Each ord In dic購入(parts)
    blc = dic購入(parts)(ord)
    If blc >= qty Then
      getQty.used = qty
      dic購入(parts)(ord) = blc - qty
    Else
      getQty.used = blc
      dic購入(parts)(ord) = 0
    End If
    getQty.PO = ord
    getQty.flag = True
    If dic購入(parts)(ord) = 0 Then
      dic購入(parts).Remove (ord)
    End If
    Exit For
  Next
  
End Function

【69773】Re:材料費の内訳作成
お礼  さとちゃん  - 11/8/28(日) 6:36 -

引用なし
パスワード
   UO3さん
確認させていただきました。理想通りのものです。
どうもありがとうございます。
先行きがとても明るくなりました。
シートレイアウトの件でご心配いただきましたが、おっしゃられる通りです。
自分で実際のデータに当て込み、行き詰ると思うので、また相談させてください。

2132 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free