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

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

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

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

Q&A

解決済

3回答

1656閲覧

可変になる出力範囲を指定して計算を実行したい

退会済みユーザー

退会済みユーザー

総合スコア0

VBA

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

0グッド

0クリップ

投稿2019/01/26 03:29

現在、商品コードを入れると、マスタから対応するオプション料金を取得する処理を作成しています。
その中で、出力範囲が可変になる場合を考慮した処理をどうすればいいのか悩んでおります。

  • マスタシート

事前に、一意の商品コードに紐づく対象項目、オプション料金、オプションコード、オプション名称が登録されている。
対象項目1、オプション料金1、オプションコード1、オプション名称1は必須だが、2以降は任意。
また、J列の横に対象項目3、オプション料金3、オプションコード3、オプション名称3...と後から項目が増える可能性がある。
イメージ説明

  • 商品シート

手動で、商品コード、数量、重さ、金額を入力する。一意の商品コードに対して数量、重さ、金額すべて登録されている。
商品コードが重複して登録されることはない。桁数は最大桁4桁。
マスタシートで項目が増えた場合、K列の横に総計3,コード3,料金名3...と増える可能性がある。
イメージ説明

処理の流れは以下になります。

  1. 商品シートに商品コード、数量、重さ、金額を入力
  2. 計算ボタンを押下すると、

商品シートの商品コード1列目から順に
マスタシートの商品項目に紐づく料金コード * 商品シートの数量、重さ、金額(いずれか)
を計算し、総計欄に出力。
計算に利用したマスタシートのオプションコードと名称も出力する。
商品シートのデータがある最後尾まで処理を実施すると、処理完了となる。

そこで以下のような処理を考えたのですが、
マスタシートの対象項目、オプション料金、オプションコード、オプション名称が後から増える可能性がある点が上手く考慮できていません。
SetOtherObjectファンクションで、対象項目の列によって検索範囲の列名を配列に設定してSetValueで計算時に配列から列番号を取り出す処理を考えていますが、SetOtherObjectファンクションで分岐するときマスタのC列かG列かという判定にしているので今後増えた場合、更に分岐を増やす...ということになって冗長化して良くないと思っています。
検索範囲をdictionaryに入れたらいいのかとも思ったのですが、いい設定方法が思いつきませんでした。。。
可変の検索範囲の設定方法についていい案があったらご教授お願い致します。
また、説明不足な点がありましたらご指摘ください。

html

1Public mash As Worksheet 2Public pdsh As Worksheet 3Public maxrow1 As Long 4Public maxrow2 As Long 5Public i As Long 6Public ma As Object 7Public masKey As String 8 9Sub CalculatePrice() 10 Dim tmpcd1 As String 11 Dim tmpcd2 As String 12 Dim tmp1(6) As String 13 Dim tmp2 As Variant 14 15 Set ma = CreateObject("Scripting.Dictionary") 16 Set mash = Sheets("マスタ") 17 Set pdsh = Sheets("商品") 18 19 maxrow1 = mash.Cells(Rows.Count, "B").End(xlUp).Row 20 21 For row1 = 3 To maxrow1 22 masKey = mash.Cells(row1, "B").Value 23 ma(masKey) = row1 24 Next 25 26 maxrow1 = pdsh.Cells(Rows.Count, "B").End(xlUp).Row 27 28 For i = 3 To maxrow1 29 masKey = pdsh.Cells(i, "B") 30 row1 = ma(masKey) 31 32 tmpcd1 = mash.Cells(row1, "C").Value 33 tmp2 = SetOtherObject(tmp1, "C", tmpcd1) 34 Call SetValue(row1, i, tmp1) 35 36 tmpcd1 = mash.Cells(row1, "G").Value 37 38 If tmpcd1 <> "" Then 39 tmp2 = SetOtherObject(tmp1, "G", tmpcd1) 40 Call SetValue(row1, i, tmp1) 41 End If 42 Next 43End Sub 44 45Function SetOtherObject(ByRef arry() As String, o As String, calitm As String) As Variant 46 47 If o = "C" Then 48 arry(1) = "D" 49 arry(2) = "E" 50 arry(3) = "F" 51 arry(4) = "G" 52 arry(5) = "H" 53 54 Select Case calitm 55 56 Case "金額" 57 arry(0) = "E" 58 Case "数量" 59 arry(0) = "D" 60 Case "重さ" 61 arry(0) = "C" 62 End Select 63 Else 64 arry(1) = "H" 65 arry(2) = "I" 66 arry(3) = "I" 67 arry(4) = "J" 68 arry(5) = "K" 69 70 Select Case calitem 71 72 Case "金額" 73 arry(0) = "E" 74 Case "数量" 75 arry(0) = "D" 76 Case "重さ" 77 arry(0) = "C" 78 End Select 79 End If 80 SetOtherObject = arry 81 82End Function 83 84Sub SetValue(row1, i, tmp) 85 Dim x As Long, y As Long, z As Long 86 x = pdsh.Cells(i, tmp(0)).Value 87 y = mash.Cells(row1, tmp(1)) 88 89 pdsh.Cells(i, tmp(3)).Value = x * y 90 pdsh.Cells(i, tmp(4)) = mash.Cells(row1, tmp(2)).Value 91 pdsh.Cells(i, tmp(5)) = mash.Cells(row1, tmp(3)).Value 92End Sub 93 94 95

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

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

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

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

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

guest

回答3

0

ベストアンサー

オプションは金額、数量、重さのみの前提です。
オプションが増えた場合でも、ループの上限を変えれば良いだけなので、修正は容易かと。
(商品シートはレイアウトの変更が必要になりますので、その箇所はマクロも修正が必要です。)

VBA

1Option Explicit 2Public mash As Worksheet 3Public pdsh As Worksheet 4Public ma_cd As Object 'キー:商品コード 値:マスタシートの行番号 5Public ma_opt As Object 'キー:商品コード 値:出現したオプション(複数あり)カンマで区切る 6Public kind_opt As Object 'キー:オプション(金額、数量、重さ等) 値:商品シートの列番号 7 8 9Public Sub オプション集計() 10 Dim maxrow1 As Long 11 Dim maxrow2 As Long 12 Dim row1 As Long 13 Dim row2 As Long 14 Dim col1 As Long 15 Dim col2 As Long 16 Dim Key As String 17 Dim Key2 As String 18 Dim i As Long 19 Dim options As Variant 20 Set ma_cd = CreateObject("Scripting.Dictionary") 21 Set ma_opt = CreateObject("Scripting.Dictionary") 22 Set kind_opt = CreateObject("Scripting.Dictionary") 23 Set mash = Sheets("マスタ") 24 Set pdsh = Sheets("商品") 25 '各オプションの列番号を記憶する 26 For col2 = 3 To 5 27 Key = pdsh.Cells(2, col2).Value 28 kind_opt(Key) = col2 29 Next 30 maxrow1 = mash.Cells(Rows.Count, "B").End(xlUp).Row 31 'マスタシートの行番号とオプションの種類を記憶する 32 For row1 = 3 To maxrow1 33 Key = mash.Cells(row1, "B").Value 34 ma_cd(Key) = row1 35 'K列までオプションを記憶する 36 For col1 = 3 To 11 Step 4 37 Key2 = mash.Cells(row1, col1).Value 38 If Key2 = "" Then Exit For 39 If kind_opt.exists(Key2) = True Then 40 If ma_opt.exists(Key) = False Then 41 ma_opt(Key) = Key2 42 Else 43 ma_opt(Key) = ma_opt(Key) & "," & Key2 44 End If 45 Else 46 MsgBox (row1 & "行 " & col1 & "列の" & Key2 & "は商品シートに未登録です") 47 Exit Sub 48 End If 49 Next 50 Next 51 52 maxrow2 = pdsh.Cells(Rows.Count, "B").End(xlUp).Row 53 '商品シートを全行分処理する 54 For row2 = 3 To maxrow2 55 'F列~N列をクリア 56 pdsh.Range("F" & row2 & ":N" & row2).Value = "" 57 Key = pdsh.Cells(row2, "B").Value 58 row1 = ma_cd(Key) 59 options = Split(ma_opt(Key), ",") 60 For i = 0 To UBound(options) 61 col1 = 3 + i * 4 62 col2 = kind_opt(options(i)) 63 pdsh.Cells(row2, 6 + i * 3).Value = pdsh.Cells(row2, col2).Value * mash.Cells(row1, col1 + 1).Value 'オプション料総計 64 pdsh.Cells(row2, 7 + i * 3).Value = mash.Cells(row1, col1 + 2).Value 'オプションコード 65 pdsh.Cells(row2, 8 + i * 3).Value = mash.Cells(row1, col1 + 3).Value 'オプション名 66 Next 67 Next 68 69End Sub 70

投稿2019/01/27 11:39

tatsu99

総合スコア5438

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

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

退会済みユーザー

退会済みユーザー

2019/01/27 11:43

ご回答ありがとうございます! ループの回し方が考えつかなかったので非常に助かりました。 このあと、教えて頂きましたコードを自分で動かして確認してみます。
guest

0

こういった「後からデーターベースに大きな変更がある設計」という設計自体が間違っています。
最大100個としてオプション料金欄を作っておき、
縦に検索の後、横にループ処理してあるかぎりのオプション料金を抽出するのが良いでしょう。
全抽出後に出力しているページの罫線や色付けを調整するようにすればよいかと思います。

どうしても「追加前提」で設計したい場合は品番・オプションのテーブル(シート)を別で作り、
そちらから抽出すればよいかと思います。
(メンテナンスが大変なので追加・削除用のUIを作れば良いと思います)

投稿2019/01/26 04:59

shinobu_osaka

総合スコア456

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

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

退会済みユーザー

退会済みユーザー

2019/01/26 06:46

ご回答ありがとうございます! なるほど、最初から固定で追加分を固定するんですね。 流石に100までふえることはなさそうなので、10位で想定してコードに修正してみようと思います!
shinobu_osaka

2019/01/26 14:13

まさかの追加でも超えないようにしておかないと、いざ超えたときがすごく面倒ですよ、多めにしておくのが良いと思います。
guest

0

すみません。
商品シートの商品CD=101,数量=5,重さ=8,金額=200の時
計算結果はどのようになるのですか。
オプション料1総計
対象オプションCD1
対象オプション名1
オプション料2総計
対象オプションCD2
対象オプション名2
に設定される値と、その計算方法を具体的に提示していただけませんでしょうか。

投稿2019/01/26 06:17

tatsu99

総合スコア5438

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

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

退会済みユーザー

退会済みユーザー

2019/01/26 06:53 編集

オプション料1総計50×200=1000 ※ ・マスタシートの商品コード101のオプション1→対象項目が金額,オプション料金が200 ・商品シートに入力された金額→50 対象オプションCD1 400 対象オプション名1 サービス料① オプション料2総額 50×8=400 ※ ・マスタシートの商品コード101のオプション2→対象項目が数量,オプション料金2が50 商品シートに入力された数量→8 対象オプションCD2 200 対象オプション名2 加工② になります! 他に不明点あればご指摘下さい。
tatsu99

2019/01/26 07:01

1)オプション料1総計50×200=1000ですが、これは 商品コード=101の金額のオプション料金が50、商品シートの金額が200なので、50×200であってますか。 2)オプション料2総額 50×8=400 これがよくわかりません。 商品コード=101の数量のオプション料金が50なので50、商品シートの数量は5なので 50×5=250ではないでしょうか。なぜ、重さの8を掛けるのかが判りません。 3)マスタのシートはK列以降に追加の予定があるとのことですが、商品シートのオプションは数量、重さ、金額となっています。つまり、最大3種類ということであってますか。もし、数量、重さ、金額の他に何か別のオプションも追加になる可能性があるのですか。もし、そうなった場合は、商品シートのE列の次にその追加オプションを割り込ませることになるのでしょうか。つまり、商品シートのレイアウトの変更が発生することになるのでしょうか。
退会済みユーザー

退会済みユーザー

2019/01/27 10:00 編集

回答が遅くなり申し訳ございません。 1)仰る認識であっています。 2)すみません、打ち間違いでした。ご指摘のとおり数量を使うので5×50になります。 3)現状、金額、重さ、数量のみになります。 他の項目の追加はしないため、項目追加によるレイアウト変更はありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問