teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

tuiki

2018/12/05 04:57

投稿

jawa
jawa

スコア3020

answer CHANGED
@@ -34,4 +34,118 @@
34
34
 
35
35
  いずれにしても、科目と商材の判断など、考え方は似たようなものになるかと思います。
36
36
 
37
+ 参考になれば幸いです。
38
+
39
+
40
+ VBAでの実装(追記2018/12/05 13:56)
41
+ ---
42
+ VBAでの実装を想定しているとのことでしたので、その前のコメントに記述した「関数(Function)の作成」について少し掘り下げてみたいと思います。
43
+
44
+ なお、「実績データB列の空欄判定では科目の判別ができない」ということも踏まえて、以下のような流れを考えてみました。
45
+
46
+ ===
47
+ ①関数の引数として、実績データ範囲と、商材名、科目のセルをそれぞれ取得する
48
+ 例えば
49
+ ・関数名:fncGetValue
50
+ ・引数1:実績データ範囲(科目・商材名と数値の2列のセル範囲)
51
+ ・引数2:商材名(セル)
52
+ ・引数3:科目(文字列)
53
+ とすると、
54
+ `=fncGetValue(A16:B100, A2, B2)`
55
+ のように指定する
56
+
57
+ ②科目をリストアップする
58
+ 商材名セルが連結セルなので、連結されている行数分だけループ処理を行い、右隣にある科目列から科目名を取得する("粗利"は含めない)
59
+ ⇒科目のリストを格納するのにはDictionaryオブジェクトの利用をお勧めします。
60
+ DictionaryにはExistsという存在チェックが用意されていますので、登録されているキーワードの確認が簡単になります。
61
+ ※Dictionaryオブジェクトを利用するには「ツール」-「参照設定」で`Microsoft.Scripting.Runtime`を追加するか、コード中でCreateObjectする必要があります。
62
+
63
+ ③実績データを1行ずつループ処理
64
+
65
+ ④実績データの1列目の値が科目ディクショナリに登録されているかチェック
66
+ ・④-a ⇒登録されていれば「科目」
67
+ 次の科目が見つかるまで、ここで見つけた科目が実績データの科目となる
68
+
69
+ ・④-b ⇒登録されていなければ「商材」
70
+ 引数で指定された科目・商材と一致する場合は2列目の値を返して処理終了。
71
+ 一致しない場合は次行の処理へ(③へ戻る)
72
+
73
+ ===
74
+ といった流れで、引数に合致する値を返せると思います。
75
+
76
+ 上記をもとにサンプルも作成してみました。
77
+ ```
78
+ Function fncGetValue(vrData As Range, vrItem As Range, vrKind As Range)
79
+
80
+ Dim ret As Double '戻り値
81
+ ret = 0
82
+
83
+ Dim i As Integer
84
+
85
+ '実績データの領域チェック
86
+ If vrData.Columns.Count < 2 Then
87
+ fncGetValue = "#Data Err"
88
+ Exit Function
89
+ End If
90
+
91
+ '科目ディクショナリ
92
+ '↓Windows.Scripting.Runtimeを参照設定に追加していない場合はこちら
93
+ 'Dim dicKinds As Object '科目ディクショナリ
94
+ 'Set dicKinds = CreateObject("Scripting.Dictionary")
95
+ '↑
96
+
97
+ '↓Windows.Scripting.Runtimeを参照設定に追加している場合はこちら
98
+ Dim dicKinds As Dictionary '科目ディクショナリ
99
+ Set dicKinds = New Dictionary
100
+ '↑
101
+
102
+ '商材セルの結合サイズから科目ディクショナリを作成
103
+ For i = 1 To vrItem.MergeArea.Rows.Count
104
+ If vrItem.Cells(i, 2) <> "粗利" Then
105
+ dicKinds.Add vrItem.Cells(i, 2).Value, 0
106
+ End If
107
+ Next
108
+
109
+ Dim strKind As String '実績データの科目
110
+ Dim strVal1 As String '実績データのA列セル値
111
+ Dim strVal2 As String '実績データのB列セル値
112
+
113
+ '対象範囲をループ処理
114
+ For i = 1 To vrData.Rows.Count
115
+ '値取得
116
+ strVal1 = vrData.Cells(i, 1).Value 'A列
117
+ strVal2 = vrData.Cells(i, 2).Value 'B列
118
+
119
+ If dicKinds.Exists(strVal1) = True Then
120
+ '科目ディクショナリにある:「科目」
121
+ strKind = strVal1
122
+ Else
123
+ '科目ディクショナリにない:「商材」
124
+ '今回の抽出対象化判定
125
+ If strKind = vrKind.Value And strVal1 = vrItem.Value Then
126
+ ''対象科目の対象商材なら戻り値に加算
127
+ 'ret = ret + Val(strVal2)
128
+
129
+ '見つけたら値を返して終了
130
+ ret = Val(strVal2)
131
+ Exit For
132
+ End If
133
+ End If
134
+ Next
135
+
136
+ fncGetValue = ret
137
+
138
+ End Function
139
+ ```
140
+
141
+ これをVBAで標準モジュールとして記述します。
142
+
143
+ 使用する際は、例えば
144
+ ・売上の値(C2セル)には`=fncGetValue(Sheet1!A$16:B$100, A2, B2)`
145
+ ・外注の値(C3セル)には`=fncGetValue(Sheet1!A$16:B$100, A2, B3)`
146
+ ・仕入の値(C4セル)には`=fncGetValue(Sheet1!A$16:B$100, A2, B4)`
147
+ のような式を記述することで、それぞれ目的の値が出力されると思います。
148
+
149
+ コメント多めにしておきましたが、不明な点等あればご確認ください。
150
+
37
151
  参考になれば幸いです。