法律事務所の仕事では、エクセルをデータベースとして使うことが多くあります。エクセルをデータベースとして使用する場合に便利な機能として、テーブル機能があるのですが、使っている人は少ないようです。
テーブル機能がどうして便利なのかについては、こちらの記事が参考になります。
そして、このテーブル機能は、VBAとの親和性が非常に高い機能でもあります。
この点に関しては、こちらの記事にが参考になります。
「VBAエキスパート公式テキスト」の「Excel VBAスタンダード」には、2019年に改訂された際に「テーブルの操作」に関する20ページ以上の記事が追加されました。つまり、VBAエキスパート試験の試験範囲に含まれたということです。このことは、このテーブルを操作できることが、VBAを習得するうえで重要なものになっていることを表しています。
「テーブルにすると何が良いのか」を説明するためには、「テーブルがないと何が問題なのか」を説明しなければなりません。その問題に実際に直面した人でなければ、理解してもらうのは極めて困難だと思いますが、一番重大な問題点を一言でいうならば、「変化に弱い」ということです。
「Excel VBAを実務で使い倒す技術」には、「『変化』は必ずやってきてVBAを劣化させる」とし、「予測できる変化に備えておく」ことや「そもそも変化に強い作り方をしておく」ことが重要だと述べられています。そういった観点で、「テーブル機能」を活用することには、大きな利点があります。
一度、テーブルを用いたVBAプログラミングを経験したならば、もう二度と元には戻れなくなるほどです。また、テーブルを用いる場合のVBAのコードは、それを用いないものとは大きく異なるため、VBAでデータベースを扱う場合には、最初から「テーブル機能」を用いるべきです。
ということで、VBAアセットでは、「表は必ずテーブルにする」というスタイルを採っています。
テーブルの特定
VBAアセットでは、テーブルを特定するのにテーブルの名前を使っています。法律事務所では、データベースを作ったら、それを更新して使い続ける場面がほとんどだと思います。次々にテーブルを自動的作成しなければならないことは、経験したことがありません。このため、テーブルに付けられた名前を使って特定するのが、最も簡単で確実な方法だと思います。
例えば、テーブル名が「テーブル」の場合、次のようにテーブルのデータ領域を特定できます。
Range("テーブル")
テーブルの最終行列番号は、次のようにして求めることができます。
テーブルを使わない場合に表の最終行を求めるのに苦労していたのが、嘘のようです。
r = Range("テーブル").Rows.Count
s = Range("テーブル").Columns.Count
Rangeの前にシート名が必要かどうかについては、次のとおりです。
・標準モジュールおよびWorkbookモジュールでは、(ブックの配下となるので)シート名は必要ない
・Sheetモジュールでは、自分のシートにテーブルがある場合のみシート名は必要ない(他のシートにテーブルがある場合はシート名を指定しないとエラーになる。)
テーブル内部の部位の特定
まずは、テーブル行列番号を使って特定することができます。特にテーブル行を0にして、見出しを特定する手法は使う場面が多いです。
Range("テーブル")(r,s) 'データ領域のr番目の行、s番目の列のセル
Range("テーブル").Cells(r,s) '同上
Range("テーブル")(0,s) '見出しのs番目の列のセル
Range("テーブル").Cells(0,s) '同上
次に構造化参照を使って、見出しを使って特定することができます。
これができることが、テーブルを使うことで得られる最大の利点です。後からテーブルの途中に新しい列を追加しても、マクロを修正する必要がなくなります。
Range("テーブル[番号]")(r) '「番号」列のr番目の行のセル
Range("テーブル[番号]").rows(r) '同上
特定の見出しの列番号を求めることも簡単です。
Range("テーブル[番号]").Column '「番号」列の列番号
データ領域の行や列全体を特定することもできます。特に「行全体」は、特定の行の書式を設定する場合にとても便利です。
Range("テーブル").Rows(r) 'r番目の行全体
Range("テーブル").Columns(s) 's番目の列全体(見出しを除く)
テーブルの位置
テーブルの位置(シートの行列番号)は、次のようにして求めることができます。
i = Range("テーブル").Row
j = Range("テーブル").Column
イベントプロシージャは、シートの行列番号しか返しませんので、イベントでテーブルを操作する場合は、これによって求めた位置でテーブルの行列番号に補正する必要があります。
r = Target.Row - Range("テーブル").Row + 1
s = Target.Column - Range("テーブル").Column + 1
参考
ListObjectsを使う方法もあります。
コメント
特定の見出しの列番号の求め方を追加しました。
Rangeの前にシートの指定が必要かどうかについて、追記しました。