質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

6478閲覧

エクセルSUMIFS高速処理をVBAで処理したい

cd987456

総合スコア33

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2020/04/11 12:42

編集2020/04/11 15:02

エクセル関数のSUMIFSをVBAを使って高速処理したいです。

”抽出”シートと”集計”シートがあります。
”抽出”シートは下図のようになっています。
イメージ説明
項目は「カテゴリ」、「部品」、「保管場所」、「推定在庫」、「実在庫」となっています。
処理結果は下図にようにしたいです。
イメージ説明

「カテゴリ」は複数あります。違うカテゴリに同じ部品が入っている場合があります。
「カテゴリ」は5つくらいです。
「部品」は10万くらいあります。
SUMIFSを使うとかなり時間が掛かります。
「計」欄は数式(SUM)を残したいです。

以前教えていただいたコードは配列(Dictionary)を使うものでした。
在庫の種類が1種類であれば、可能なのですが、2種類になると分からなくなってしまいました。
コードを教えて下さい。

以前のコード
「集計」シートに縦軸に部品、横軸にカテゴリ、中の数字が足し算した結果が表示されています。

Public Sub サンプル() Dim dic As Object, dicE As Object Dim vA As Variant, vK As Variant, v As Variant Dim i As Long, j As Long, k As Long Dim LINE As Integer Set dic = CreateObject("Scripting.Dictionary") Set dicE = CreateObject("Scripting.Dictionary") With Worksheets("抽出") With .Range("A1", .Cells(Rows.Count, "A").End(xlUp)) vA = .Resize(, 4).Value End With End With For i = 2 To UBound(vA) If (Not dic.Exists(vA(i, 2))) Then dic.Add vA(i, 2), CreateObject("Scripting.Dictionary") End If dic(vA(i, 2))(vA(i, 1)) = dic(vA(i, 2))(vA(i, 1)) + vA(i, 4) dicE(vA(i, 1)) = Empty Next ReDim vA(1 To dic.Count + 5, 1 To dicE.Count + 1) v = mySort(dicE.Keys) For i = 0 To UBound(v) j = i + 2 vA(1, j) = v(i) dicE(v(i)) = j If (j > 2) Then vA(3, j) = vA(3, j - 1) vA(4, j) = vA(4, j - 1) End If Next i = 6 For Each vK In mySort(dic.Keys) vA(i, 1) = vK For Each v In dic(vK).Keys vA(i, dicE(v)) = dic(vK)(v) Next i = i + 1 Next Application.ScreenUpdating = False With Worksheets("集計") .Cells.Delete With .Range("A1").Resize(UBound(vA), UBound(vA, 2)) .Value = vA End With .Activate End With Range("A1") = "カテゴリ" Range("B1") = "部品" Application.ScreenUpdating = True Set dic = Nothing Set dicE = Nothing MsgBox "終了しました" End Sub Private Function mySort(ByVal vA As Variant) As Variant Dim v As Variant Dim i As Long, j As Long For i = LBound(vA) To UBound(vA) - 1 For j = i + 1 To UBound(vA) If (vA(i) > vA(j)) Then v = vA(i) vA(i) = vA(j) vA(j) = v End If Next Next mySort = vA End Function

例ではカテゴリが2つですが、4個の場合は下図のようにしたいです。
イメージ説明
集計する時、保管場所は無視して足し算します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatsu99

2020/04/11 14:43

カテゴリが5つくらいとのことですが、 カテC、カテD、カテEがあった場合、レイアウトはどのようにしたいのでしょうか?
cd987456

2020/04/11 15:03

質問欄を更新してレイアウトを追記しました。
sazi

2020/04/11 15:34

> SUMIFSを使うとかなり時間が掛かります。 現状どの程度の時間が掛かっていて、目標はどの位なんでしょう?
cd987456

2020/04/11 16:53

処理する毎に部品の数が違うのですが、今回の場合は抽出シートが約11万行で、集計シートの部品は約4万でした。カテゴリは2つでした。処理は約10分~15分くらいでした。 可能であれば、1分~2分くらいにしたいです。
otn

2020/04/11 17:17

ピボットを使えばよい気がしますが。
guest

回答1

0

ベストアンサー

以下のようにしてください。
集計シートの2行目の見出しはマクロで設定します。
集計シートの1行目の見出しはマクロで設定しません。(手作業で設定しておいてください)
A列は部品でソート、2行目はカテゴリでソートしています。
(あなたが提示されたソート処理をそのまま使っています)

VBA

1Option Explicit 2 3 4Public Sub 集計() 5 Dim dicCA As Object 'カテゴリ  キー:カテゴリ 値:true 6 Dim dicP1 As Object '部品単位在庫  キー:部品 値:推定合計 7 Dim dicPC1 As Object '部品・カテゴリ単位在庫 キー:部品+カテゴリ 値:推定合計 8 Dim dicP2 As Object '部品単位在庫  キー:部品 値:実在庫合計 9 Dim dicPC2 As Object '部品・カテゴリ単位在庫 キー:部品+カテゴリ 値:実在庫合計 10 Dim sh1 As Worksheet 11 Dim sh2 As Worksheet 12 Dim maxrow1 As Long 13 Dim row1 As Long 14 Dim row2 As Long 15 Dim key1 As Variant 16 Dim key2 As Variant 17 Dim key3 As Variant 18 Dim cate As Variant 'ソート済みカテゴリ配列 19 Dim parts As Variant 'ソート済み部品配列 20 Dim i 21 Set sh1 = Worksheets("抽出") 22 Set sh2 = Worksheets("集計") 23 Set dicCA = CreateObject("Scripting.Dictionary") ' 連想配列の定義 24 Set dicP1 = CreateObject("Scripting.Dictionary") ' 連想配列の定義 25 Set dicPC1 = CreateObject("Scripting.Dictionary") ' 連想配列の定義 26 Set dicP2 = CreateObject("Scripting.Dictionary") ' 連想配列の定義 27 Set dicPC2 = CreateObject("Scripting.Dictionary") ' 連想配列の定義 28 maxrow1 = sh1.Cells(Rows.Count, 1).End(xlUp).row 'sheet1 最終行を求める 29 Application.ScreenUpdating = False 30 31 For row1 = 2 To maxrow1 32 'カテゴリ 33 key1 = sh1.Cells(row1, "A").Value 34 If dicCA.exists(key1) = False Then 35 dicCA(key1) = True 36 End If 37 '部品 38 key2 = sh1.Cells(row1, "B").Value 39 If dicP1.exists(key2) = False Then 40 dicP1(key2) = sh1.Cells(row1, "D").Value '推定在庫設定 41 dicP2(key2) = sh1.Cells(row1, "E").Value '実在庫設定 42 Else 43 dicP1(key2) = dicP1(key2) + sh1.Cells(row1, "D").Value '推定在庫加算 44 dicP2(key2) = dicP2(key2) + sh1.Cells(row1, "E").Value '実在庫加算 45 End If 46 '部品+カテゴリ 47 key3 = sh1.Cells(row1, "B").Value & "|" & sh1.Cells(row1, "A").Value 48 If dicPC1.exists(key3) = False Then 49 dicPC1(key3) = sh1.Cells(row1, "D").Value '推定在庫設定 50 dicPC2(key3) = sh1.Cells(row1, "E").Value '実在庫設定 51 Else 52 dicPC1(key3) = dicPC1(key3) + sh1.Cells(row1, "D").Value '推定在庫加算 53 dicPC2(key3) = dicPC2(key3) + sh1.Cells(row1, "E").Value '実在庫加算 54 End If 55 Next 56 57 'カテゴリソート 58 cate = mySort(dicCA.keys) 59 '部品ソート 60 parts = mySort(dicP1.keys) 61 '集計シートの2行目以降をクリア 62 sh2.Rows("2:" & Rows.Count).ClearContents 63 '集計シートの見出し設定 64 For i = 0 To UBound(cate) 65 sh2.Cells(2, 2 + i).Value = cate(i) 66 sh2.Cells(2, 4 + UBound(cate) + i).Value = cate(i) 67 Next 68 sh2.Cells(2, 2 + UBound(cate) + 1).Value = "合計" 69 sh2.Cells(2, 4 + 2 * UBound(cate) + 1).Value = "合計" 70 71 '部品数繰り返す 72 For i = 0 To UBound(parts) 73 row2 = i + 3 74 sh2.Cells(row2, "A").Value = parts(i) '部品 75 Call output(sh2, parts(i), row2, cate, 2, dicPC1, dicP1) '推定在庫設定 76 Call output(sh2, parts(i), row2, cate, UBound(cate) + 4, dicPC2, dicP2) '実在庫設定 77 Next 78 Application.ScreenUpdating = True 79 MsgBox ("完了") 80End Sub 81 82Private Sub output(ByVal sh2 As Worksheet, ByVal part As String, ByVal row2 As Long, ByVal cate As Variant, ByVal scol As Long, ByVal dicPC As Object, ByVal dicP As Object) 83 Dim i As Long 84 Dim col2 As Long 85 Dim key3 As Variant 86 For i = 0 To UBound(cate) 87 col2 = scol + i 88 key3 = part & "|" & cate(i) 89 If dicPC.exists(key3) = True Then 90 sh2.Cells(row2, col2).Value = dicPC(key3) 91 Else 92 sh2.Cells(row2, col2).Value = 0 93 End If 94 Next 95 sh2.Cells(row2, scol + UBound(cate) + 1).Value = dicP(part) 96End Sub 97 98Private Function mySort(ByVal vA As Variant) As Variant 99 Dim v As Variant 100 Dim i As Long, j As Long 101 102 For i = LBound(vA) To UBound(vA) - 1 103 For j = i + 1 To UBound(vA) 104 If (vA(i) > vA(j)) Then 105 v = vA(i) 106 vA(i) = vA(j) 107 vA(j) = v 108 End If 109 Next 110 Next 111 mySort = vA 112End Function 113

投稿2020/04/14 03:40

tatsu99

総合スコア5438

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cd987456

2020/04/14 15:00

ありがとうございます。すごいです。丁寧なコメントもありがとうございます。 今日は部品が3万くらいでした。処理が30秒くらい。すごく助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問