テーブルのデータ数をカウントする方法が分かります。
これを利用して、テーブルの複数の列範囲をいっきに取得する方法をご紹介します。
-
データ(レコード)数を数える
テーブルオブジェクト.ListRows.Count
-
抽出後のデータ(レコード)数を数える
テーブルオブジェクト.ListColumns(1).DataBodyRange.SpecialCells(xlCellTypeVisible)
-
複数の列の範囲を一気に取得する
Range(テーブルオブジェクト.ListColumns(最初の列).Range(1), テーブルオブジェクト.ListColumns(最後の列).DataBodyRange(テーブルオブジェクト.ListRows.Count))
- 関数を作りました。フィルター後、前対応。該当なしなら0を返す
こんにちは、hokkyokunです。
テーブルのデータ(専門用語でレコードといいます)の数を数える方法をご紹介します。
データの数を数えること自体も重要ですが、
データ(レコード)の一番下の位置を取得することにも使えます。
それが何の役に立つか?活用方法も解説します。
テーブルの部位の名称について
基本的な事項ですが、
テーブルは
- 見出し:テーブルオブジェクト.HeaderRowRange
- データ(レコード):テーブルオブジェクト.DataBodyRange
- 集計行:テーブルオブジェクト.TotalsRowRange
の三つの部位から出来ています。
これを図にするとこんな感じです。
それぞれの位置を取得するには
例えばデータ(レコード)の一行目の左端であれば
テーブルオブジェクト.DatabodyRange(1)とインデックス番号で指定します。
一行目の二番目は テーブルオブジェクト.DatabodyRange(2)です。
データ(レコード)全体を指すには
テーブルオブジェクト.DatabodyRangeと指定します。
データ(レコード)の数を数えるにはListRows.Count
基本的な操作
構文:テーブルオブジェクト.ListRows.Count
使ってみましょう。
例えば、こんな感じで表を作ったとし、
データ(レコード)の数を数えてみます。
Sub データ数カウント()
Dim table As ListObject
Set table = ActiveSheet.ListObjects(1)
MsgBox ("データ(レコード)の数は:" & table.ListRows.Count)
End Sub
データの数を数えることが出来ました。
抽出後のデータの数
次は抽出後のデータの数を数えて見ましょう。
上記のプログラムをそのまま動かしてみると・・・
変わらず、7です。
このプログラムはテーブルのデータ数のカウントなので、
抽出後(見えている行)のカウントはしてくれません。
SpecialCellsプロパティを使います。
構文:テーブルオブジェクト.ListColumns(1).DataBodyRange.SpecialCells(xlCellTypeVisible)
SpecialCellsは文字通り特殊なセルのみを取得するプロパティで
引数を xlCellTypeVisible にすることで
抽出後(=見えている行)のセルのみを取得することが出来ます。
注意するべきはListColumnsを使っていることです。
考え方としては
一つの列(=listColumns(1)とするのが無難)のデータ(レコード)の中の特殊なセル(=Specialcells(xlCellTypeVisible))の数を数える
ということです。
プログラムはこうなります。
Sub 抽出後データ数カウント()
Dim table As ListObject
Set table = ActiveSheet.ListObjects(1)
MsgBox ("データ(レコード)の数は:" & table.ListColumns(1).DataBodyRange.SpecialCells(xlCellTypeVisible).Count)
End Sub
データの一番下のセル位置を取得する方法
さて、上記の方法を使えばデータ(レコード)の最下段の位置を取得することが出来ます。
先ほどから使用している表で最下段(スイカ)を取得してみようと思います。
Sub データの最下段の取得()
Dim table As ListObject
Set table = ActiveSheet.ListObjects(1)
dim maxRow as long
MsgBox ("「果物」列のデータ(レコード)の最下段の位置は:" & table.ListColumns("果物").DataBodyRange(table.ListRows.Count).Address & vbCrLf & _
"「果物」列データ(レコード)の最下段の値は:" & table.ListColumns("果物").DataBodyRange(table.ListRows.Count).Value)
End Sub
範囲取得が出来る
どうしてデータの最下段を取得する必要があるかというと
テーブルの範囲を取得するときに使えるからです。
テーブルの範囲取得って基本的には
- 見出し、データ(レコード)、集計行を全体がばっととるか
- 列の中の 見出し、データ(レコード)、集計行 をとるかしか想定されていません。
なので、下記でいうところの「日付」列から「スーパー」列の範囲を取得するってなると
意外にハードルが高いです。
ベタ打ちでよければいくらでも作るんですが、
列が増えたり減ったり、データが増えたり減ったりしても大丈夫な表を作るには
選択肢は限られてきます。
これが唯一の方法ではないですが、
私は割りと好きな方法なので、ご紹介しておきます。
Sub 特定の複数列範囲の取得()
Dim table As ListObject
Dim Rng As Range
Set table = ActiveSheet.ListObjects(1)
Set Rng = Range(table.ListColumns("日付").Range(1), table.ListColumns("スーパー").DataBodyRange(table.ListRows.Count))
MsgBox ("「日付」列から「スーパー」列までの範囲は:" & Rng.Address)
End Sub
Unionでつなげることでももちろん作れます。
たくさんの列をつなげるとなると、
大変だし、For文でつなげることを考えると案外コード少なく処理できるかなと思います。
テーブルは自由に処理できる部分とそうでもない部分があり、ちょっと面倒ですが、
使うメリットは大きいと思いますので、うまく処理してければと思います。
ではでは。
【追記】関数を作りました。
久々にマクロ触ってテーブルのカウントをする必要があったので
関数作りましたので共有させていただきます。
Function count_Table_rows(ByVal table As ListObject, ByVal visibleRow As Boolean)
If Not visibleRow Then
count_Table_rows = table.ListRows.Count
Else
On Error GoTo Err
count_Table_rows = table.ListColumns(1).DataBodyRange.SpecialCells(xlCellTypeVisible).Count
End If
Err:
If Err.Number = 1004 Then
count_Table_rows = 0
End If
End Function
簡単に使い方をご紹介します。
引数 | table | 対象となるテーブル データ型はlistobject |
visibleRow | フィルター後の行数を調べたいならTrue フィルターをかけないテーブル全行数はFalse | |
戻り値 | 行数 フィルターをかけて該当がなければ0を返す |
例えばざっくりですが、以下のような表があったとします。
ここからリンゴだけ抽出します。
行全体のカウントと抽出後の行数をカウントしてみます。
Sub test()
Dim table As ListObject
Set table = ThisWorkbook.Worksheets(1).ListObjects(1)
'フィルター後の「リンゴ」行の数
Dim count_appleRows As Integer
count_appleRows = count_Table_rows(table, True)
Debug.Print ("リンゴ行:" & count_appleRows)
'テーブル全体の数
Dim count_allRows As Integer
count_allRows = count_Table_rows(table, False)
Debug.Print ("テーブルの全行:" & count_allRows)
End Sub
次にVBAでフィルターをかけて該当なしになった場合を試してみます。
Sub test2()
Dim table As ListObject
Set table = ThisWorkbook.Worksheets(1).ListObjects(1)
table.Range.AutoFilter field:=table.ListColumns("果物").Index, Criteria1:="リン"
'フィルター後の行数
Dim count_nothingRows As Integer
count_nothingRows = count_Table_rows(table, True)
Debug.Print ("フィルターの行:" & count_nothingRows)
End Sub