3.VBAの命令に置き換える(コーディング)
完璧なアルゴリズムを考えるのは、処理が複雑なほど難しくなりますので、実際にはある程度大まかな処理の流れを描いたら、具体的な命令(VBAコード)に置き換えてみます。
ではまず最初に並び替えの部分をVBAの命令に置き換えてみましょう。
この部分はマクロ記録を利用できますので、「ツール」→「マクロ」→「新しいマクロの記録」を実行して、
A1からB10までを選択した状態で「データ」→「並び替え」を実行します。並び替えのキーに「書籍コード」を選択して並び順を昇順にします。
そにまま実行すると書籍コードの若い順にデータが並び変わります。並び替えが完了したらマクロ記録を解除して、コードを確認(Alt + F11)してみてください。
図4
このままでも取りあえずはOKですが、後で見たとき分かりづらいので必要な部分だけを残して、後は削除することにしましょう。
選択した範囲に対してSortメソッドが実行されていますが、後ろに引数がたくさん並べて記述されています。この引数の中から必要なものだけを残すことにします。
まずKey1は並べ替えのキーとなる項目を指定してるので必要です。
Order1は項目の並び順を指定しています。省略した場合もxlAscending(昇順)になりますが、後から見てもわかりやすいように残しておくことにしましょう。
HeaderでxlGuessを指定すると、範囲の先頭行がタイトル行であるかどうかを自動的に判断します。
ここもxlGuessのままにしておきます。先頭行がタイトル(見出し)の場合は、自動的にデータ行のみソートします。
後はOrderCustom、MatchCase、Orientation、SortMethodですが、これらは省略しても今回の場合あまり問題ないのですべて削除することにします。
それぞれの意味を知りたい方はヘルプを参照してください。
これでかなり見やすくなりましたが、コードを実行する上で、少し無駄な動きがあります
それは、いったんRange("A1:B10").Selectでデータ範囲を選択しておいて、それからSortメソッドを実行している部分です。
ここは直接Range("A2:B10").Sortと1行で記述しても、問題ありません。
むしろ1行で記述しなければ、Selectメソッドを実行後にSortメソッドを実行する、という無駄な動作が入ってしまいます。
実際の操作では仕方ない動作ですが、コードで実行させる場合はもっと効率よく動作させるために修正が必要なところです。
ではこのコードを別に名前を付けてサブプロシージャとして書き直しましょう。
「挿入」→「プロシージャ」を選択し、プロシージャ名(Shuukei)を入力してください。
サブプロシージャの枠が作られたら、先ほどのソートのコードを転写します。
’(アポストロフィ)を付けると、コメント行(緑色の文字部分)となり、可読性が増します。
図5(修正後)
次はいよいよ集計処理の部分です。
フローチャートを見ると、まず1件目のデータを読み込んでいます。
これは具体的には、ワークシートの2行目1列目セル(A2)の書籍コードを取得し、その値の先頭から1桁目の文字列を取り出す操作になります。
何だか大変そうですけどやってみましょう。
まず2行目1列目のセルの値を取得するにはCellsオブジェクトを使ってCells(2,1).Valueと表現します。書式はCells(行,列).Valueです。
取得した値はしばらく記憶しておく必要があるので、変数KEYを文字列型で宣言してその中に入れます。変数とはコンピュータに値を一時的に記憶させておく箱のようなものです。
Dim KEY As String
KEY = Cells(2, 1).Value
さらに値の先頭(左側)から1桁目を取り出すには、Left関数を使って上記の式を次のように書き換えます。
Dim KEY As String
KEY = Left(Cells(2, 1).Value, 1)
では連続してセルの値を取得するにはどうしたらよいでしょう?
実はVBAには繰り返しを行わせるのにDo〜Loopという便利な命令があります。
繰り返しの終わりを判断するためにはいくつかの書き方がありますが、ここでは「Do While 繰り返し条件式」の書式で表現してみます。
Dim KEY As String
Dim sKEY As String
Dim i As Long
i = 2
KEY = Left(Cells(i, 1).Value, 1)
Do While KEY <> ""
If KEY <> sKEY Then
'小計を出力
'小計をクリア
End If
'小計に加算
sKEY = KEY
i = i + 1
KEY = Left(Cells(i, 1).Value, 1)
Loop
では、このループ処理の説明をしていきましょう。
冒頭で変数iとsKEYを宣言していますが、これは次に計算の対象となるセルの行番号を指定するためと、現在のKEYの保存用(次のKEYと比較するため)に使います。
個々の具体的な処理については、次の段階で説明をする予定のため、今はコメントだけにしています。
まずループに入る前にiに2を代入し、読み取るべき最初のセル位置を決定します。
そして、1件目つまり2行目A列のセルの値を取り出し、その1桁目を変数KEYに格納します。
その後ループに入り、ループ内の処理に入る前に繰り返し条件をまずチェックします。
Do While KEY <> ""は、「変数KEYの中身が空白(ブランク)でない間、Do以下の処理をLoopまで繰り返す」という意味です。
セル番地A11まで連続で読み込むと空欄になるので、そうしたらループを抜け出しなさいということです。
空欄でない間はDo以下の命令を実行していきます。
まずKEYと1つ前に読み込んだsKEYの値をIf文(If KEY <> sKEY Then)で比較します。
比較の評価が真(True)の場合(つまりKEYとsKEYの値が異なる場合)は小計の出力処理が実行されます。
偽(False)の場合(つまりKEYとsKEYの値が等しい場合)は次のステップに移動します。
図6 分類コードの切れ目を調べる
次のステップでは現在の金額を小計に加算し、KEYの値をsKEYに保存します。
そして変数iの値を1つ増やし、次のデータを読み込みます。
これらをA列が空欄の行まで、繰り返させます。
次はコメントで説明していた処理を、具体的なコードに置き換えていきましょう。
「小計を出力」の処理は変数Shoukeiの値を、ある場所のセルに書き込む操作となりますので、Cells(j, 5).Value = Shoukeiのような書き方になります。
j行の5列目(E列)に書き込むわけです。
なおjは出力行を示す変数です。当然変数iと同じように宣言して、実行前に値を代入しておく必要があります。
「小計をクリア」は簡単ですね。変数Shoukeiに0(ゼロ)を代入してあげればクリアされます。
「小計に加算」は、まずサブプロシージャの先頭で小計を記憶しておくための変数ShoukeiをCurrency型で宣言しておきます。(データ型については変数の基本データ型を参照)
金額はi行の2列目(B列)に入っているので、Shoukei = Shoukei + Cells(i, 2).ValueでShoukeiに足しこむことができます。
今まで説明してきた部分をコードでもう一度表してみると、次のようになります。
最後に、もう一度残りの小計を出力させる部分も追加しておきましょう。
Dim KEY As String
Dim sKEY As String
Dim Shoukei As Currency
Dim i As Long
Dim j As Long
i = 2 : j = 2
KEY = Left(Cells(i, 1).Value, 1)
Do While KEY <> ""
If KEY <> sKEY Then
Cells(j, 5).Value = Shoukei
j = j + 1
Shoukei = 0
End If
Shoukei = Shoukei + Cells(i, 2).Value
sKEY = KEY
i = i + 1
KEY = Left(Cells(i, 1).Value, 1)
Loop
Shoukei = Shoukei + Cells(i, 2).Value
Cells(j, 5).Value = Shoukei
では全体のサブプロシージャShuukeiを確認しましょう。
図7
4.誤りを見つけて修正(デバッグ)する
それでは一応集計マクロらしきものが完成したので、さっそく実行してみましょう。
Sheet1を開いておき、Alt + F8キー でマクロのダイアログボックスを表示し、「Shuukei」マクロを選択して「実行」キーを押してください。
どのような結果になったでしょうか?
図8
少しこちらが期待していた結果と違う出力となりました。どうも分類コードA、B、Cに対する小計額が1つづつずれて表示されているようです。
どこがいけなかったのでしょうか?
もう一度小計出力部分のコードを見てみましょう。
1つ前の分類コードと比較して、異なっていたら小計を出力していますが、このコードではそもそも1件目のデータを処理する場合もsKEYと比較しています。
当然1件目を処理する時点ではまだsKEYには何も分類コードは入っていませんから、比較を行えばIf文の評価は真(True)となってしまい、いきなり小計を出力してしまいます。
ここは1件目のデータについては例外的に小計出力処理をスキップするようにしなければならないのでした。
したがって次のようなコードに改めることにします。
If KEY <> sKEY And i > 2 Then
Cells(j, 5).Value = Shoukei
j = j + 1
Shoukei = 0
End If
小計を出力する条件を追加して、「分類コードが等しくなく、且つ、行番号(変数i)が2より大きい場合」とします。
これで小計出力が正しく表示されるようになりました。
実行結果は次のようになります。
図9
ただこのコードではまだ全体の合計額が出力されていません。合計額は直接セルE5にSUM関数を埋め込んでもいいわけですが、これも練習ですのでマクロで集計しましょう。
図10 合計まで含めた集計マクロ