Excel VBA 事例 演習 基礎問題 part1

はじめに

ExcelVBAに関していえば、文法的なことを説明するための問題が多いが、ここでは初めに課題、事例を提示して、マクロプログラミングを行うことで必要なことを解説していく。

引用/参考文献は

業務改善コンサルタントが教えるExcel VBA自動化のすべて 35の事例で課題解決力を身につける 2023年1月10日 初版 著者:永井雅明 技術評論社

である。

問題1

目標とするデータと入力の形

実際の入力画面とデータはこの図のようになっている
問題のデータと入力画面
D 商品名 原価
1595-4615 【ミニカー】メルセデスベンツ300SL 24,500
     
商品ID 商品名 原価
1156-2510 鉄道模型ななつ星8両セット 98,500
1156-2511 鉄道模型】キハ56系急行編成3両セット 328,000
1156-2512 鉄道模型スーパーあずさ8両セット 715,000
1595-4612 【ミニカー】ジャガーEタイプ 55,700
1595-4613 【ミニカー】ロールスロイス ゴースト  69,200
1595-4614 【ミニカー】ポルシェ904GTS 56,900
2094-7822 【プラモデル】宇宙戦艦ヤマト 49,800
2094-7823 【プラモデル】銀河鉄道999ミニカコレ777 12,500

上記のデータに対して、上の2行目のデータを表の最終行に追加するプログラムを作成せよ。ただし、マクロをキックさせるときは、セルに埋め込んだコマンドボタンをつかうこと。

解答

セルにコマンドボタンを登録する方法は、ユーザーフォームpart1を見て欲しい。

コード

Option Explicit
Option Base 1
Public lrn As Integer, lcn As Integer

ーーーーーーーーーーーーーーーーーーーーーーー

Sub main()
    Call lastRowNum
    Call lastClmnNum
    Call inpData
    Call delData
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub lastRowNum()
    lrn = Cells(Rows.Count, 1).End(xlUp).Row
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub lastClmnNum()
    lcn = Cells(1, Columns.Count).End(xlToLeft).Column
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub inpData()
    Cells(lrn + 1, 1).Value = Cells(2, 1).Value
    Cells(lrn + 1, 2).Value = Cells(2, 2).Value
    Cells(lrn + 1, 3).Value = Cells(2, 3).Value
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub delData()
    Range(Cells(2, 1), Cells(2, 3)).ClearContents
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

これは広域変数とサブルーチンの練習として取り上げた。

コード自体に特に説明を有するものはないだろう。ただ、サブルーチンのlastClmnNumは作っただけで使用はしていない。

セルのコマンドボタンにはmainを登録して使用する。以下、基本的にコマンドボタンに割り付けるルーチンはmainとなる。

また、本来はこのような入力情報に対しては、ユーザーフォームを使う方がいい.。最後にユーザーフォームを使ったプログラムを紹介する。

問題2

目標とする形とデータ

実際のデータと転記先はこのような配置になっている。目標の図
データ
仕入 商品 数量
6/6 蛍光ペン 7
6/7 蛍光ペン 28
6/8 蛍光ペン 19
6/9 蛍光ペン 3
6/10 蛍光ペン 19
6/6 ホッチキス 12
6/7 ホッチキス 6
6/8 ホッチキス 11
6/9 ホッチキス 23
6/10 ホッチキス 5

 

  日付
商品
6/6 6/7 6/8 6/9 6/10
蛍光ペン          
ホッチキス          

上記のデータ表を下記の表に転記するとき、

1)For Next文とIf文のみで記述せよ。

2)For Each文とFor NextとIf文で記述せよ。

注意

ここでは表を上下に書いたが、実際は上の表の横に下の表が書いてある。目標の図を参照のこと。

解答

いまどき、リスト形式の表をクロス集計するプログラムは古臭い。ピボットテーブルを使えばことが足りる。また、クロス集計からリスト形式にするにはパワークエリを使えば簡単に変換することができる。

ここでの狙いは2通りの繰り返し処理と分岐処理をマスターすることである。

1)コード

Option Explicit
Option Base 1
Dim grd As Integer, gcd As Integer, gnr As Integer

ーーーーーーーーーーーーーーーーーーーーーーー

Sub main()
    
    Call getListDt
    Call compareDt

End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub getListDt()
    grd = Cells(Rows.Count, 1).End(xlUp).Row
    gcd = Cells(1, Columns.Count).End(xlToLeft).Column
    gnr = Cells(Rows.Count, 7).End(xlUp).Row
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub compareDt()
    Dim i As Integer, j As Integer, k As Integer
    
    For i = 2 To grd
        For j = 8 To gcd
            For k = 2 To gnr
                If Cells(i, 1) = Cells(1, j) And Cells(i, 2) = Cells(k, 7) Then
                    Cells(k, j) = Cells(i, 3)
                End If
            Next k
        Next j
    Next i
    
    ActiveWorkbook.Save
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

grdは元表の最終行をとっている。gcdとgnrは転記する表の最終の列数と行数をとっている。

If文のなかのandは元表と転記先の2つが一致したら、という意味である。

2)コード

Option Explicit
Option Base 1

Public gdt As Variant

ーーーーーーーーーーーーーーーーーーーーーーー

Sub main()
    Call getDataTable
    Call inpNewTable
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub getDataTable()
    gdt = Range("A1").CurrentRegion
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Sub inpNewTable()
    Dim i As Integer
    Dim dys As Date
    Dim gds As String
    Dim rng As Range
    
    For Each rng In Range("H2:L3")
        dys = Cells(1, rng.Column).Value
        gds = Cells(rng.Row, 7).Value
        For i = 2 To 11
            If dys = gdt(i, 1) And gds = gdt(i, 2) Then
                rng.Value = gdt(i, 3)
            End If
        Next i
    Next rng
 End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

広域変数でgdtをバリアント型で取っている。バリアント型は使わないのが定石だと、かなり多くの本やブログなどで書いてあるが、様々な型、たとえば日付のDate、文字列のString、数値のIntegerなどが混在している場合には、バリアント型を使うしか手はない。

使わないのが定石ではなく、定石なのは型を明示することである。

また、型でRangeを使った場合、SetステートメントでRangeを規定してやらなければならないのだが、例外的にFor Each文で使う場合は、Setステートメントは必要ない。

問題1のユーザーフォーム版

目標とする形。ラベルとテキストボックスを3つずつ、コマンドボタンを1つ使っている

ユーザーフォームpart2でラベル、テキストボックス、コマンドボタンの説明はしてあるので、細かいことは、そちらを参照して欲しい。

ここでは、コードを紹介するのみで十分だと思う。

標準モジュールのコード

Option Explicit
Option Base 1
Public lrn As Integer

ーーーーーーーーーーーーーーーーーーーーーーー
Sub main()
    UserForm1.Show
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー
Sub lastRowNum()
    lrn = Cells(Rows.Count, 1).End(xlUp).Row
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

ユーザーフォームのコード

Option Explicit
Option Base 1

ーーーーーーーーーーーーーーーーーーーーーーー

Private Sub UserForm_Initialize()
    Call lastRowNum
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Private Sub CommandButton1_Click()
    ActiveWorkbook.Save
    Call lastRowNum
    TextBox1 = ""
    TextBox2 = ""
    TextBox3 = ""
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Private Sub TextBox1_Change()
    Cells(lrn + 1, 1) = TextBox1.Text
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Private Sub TextBox2_Change()
    Cells(lrn + 1, 2) = TextBox2.Value
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

Private Sub TextBox3_Change()
    Cells(lrn + 1, 3) = TextBox3.Value
End Sub

ーーーーーーーーーーーーーーーーーーーーーーー

 

サイトご利用方法

次のページ・前のページを利用するよりも、グローバルメニュー(ヘッダー部分にある項目)・サブメニュー記事の項目をクリックしていただければ、その項目の全体像が一目でみることができ、クリックすればそのサイトへ飛びます。

google、yahoo、Bingなどで検索する場合、検索ワードは先頭に、孤立じじい、と入力しその後に、グローバルメニュー・サブメニュー記事のどれかひとつの項目を入力すると、その検索サイトが上位表示されます。