テーブルの部位を特定する


ListObjectでの特定

Range("A1").ListObjectがテーブル全体を表します。テーブル内の特定部位は、次のように指定します。

見出しを含むテーブル全体

Range("A1").ListObject.Range

今までセルを操作するマクロに慣れている方が、もっとも戸惑うのがこのRangeです。よろしいですか、ここは頑張って"考え方"を変えてください。セルを指し示すとき「Range("A1")」のように使うRangeと、ここで使うRangeはまったく意味が異なります。Range("A1").ListObject.RangeのRangeは、テーブル内の全セルを表します。したがって、全セル内の"何番目のセル"というのを、次のように表します。

Range("A1").ListObject.Range(3)
Range("A1").ListObject.Range(6)

ええっ!何なの?Rangeで意味が違うの?
じゃRange("A1")のRangeって何?
このRangeとどういう関係なの?何なの?

という方はVBAに向いていないのであきらめてください。ここは「そういうものなんだ」と飲み込んで「そうか違うのか」と納得するところです。そうでないと先に進めません。このRangeが何なのかは、上級者になれば分かることです。

見出しを含まないテーブルのデータ全体

Range("A1").ListObject.DataBodyRange

このDataBodyRangeも先のRangeと同様に"全セル"を表していますので、同じように"何番目のセル"を数値で指定できます。

見出し(タイトル)

Range("A1").ListObject.HeaderRowRange

見出し(タイトル)は1行だけです。ここには「見出しを含む」や「実データだけ」の区別はありませんから、次のように"何番目のセル"を数値で指定できます。

テーブル内の列は、ListColumnオブジェクトで表されます。

ListColumnオブジェクトの集合体(コレクション)がListColumnsコレクションです。

したがって、特定の列を指定するときは、次のように「何番目の列」または「何という列」という書き方をします。

Range("A1").ListObject.ListColumns(2)
Range("A1").ListObject.ListColumns("名前")

さあ、ここに、先のRangeDataBodyRangeの考え方が加わります。Rangeは「見出しを含む全体」でしたね。DataBodyRangeは「見出しを含まない実データ全体」です。

テーブル内の行は、ListRowオブジェクトで表されます。

ListRowオブジェクトの集合体(コレクション)がListRowsコレクションです。

ListRowsコレクションには、見出し(タイトル)行が含まれていない点に留意してください。

行内の、任意のセルを指定するときは、今までと同じように「何番目のセル」と指定しますが、ここで注意が必要です。ListRowオブジェクトは"行全体"を表します。"行全体のセル"ではありません。したがって、行内のセルを特定するには、ListRowオブジェクトにRangeをつけます。

集計行がある場合

テーブルには、最下行に集計行を表示することができます。テーブルに集計行を表示するには、[テーブルツール]-[デザイン]タブの[集計行]チェックボックスをオンにするか、Ctrl + Shift + T を押します。

テーブルに集計行が表示されている場合、Rangeは集計行を含み、DataBodyRangeは集計行を含みません

集計行を特定するときは、TotalsRowRangeを使います。

テーブルの名前での特定(構造化参照)

テーブルを特定するには

  1. Range("A1").ListObject
  2. Range("テーブル1")

という2つの方法がありますが、1.はテーブルを表す「ListObjectオブジェクト」のことであり、2.はテーブル内の「セル(Rangeオブジェクト)」を指しています。ほとんどの場合、両者は同じ操作ができますが、この概念の違いをしっかり認識しておくと、無駄なトラブルを回避できます。

Range("テーブル1")形式でテーブルを指定するときは、構造化参照を使って、テーブル内の部位を特定します。構造化参照とは、次のような使い方です。

ワークシート上でテーブル内のセルを参照するとき、
テーブル名[[特殊項目指定子],[列指定子]]

のように使います。セルに「=テーブル1[」まで入力すると、そのテーブルで使用できる特殊項目指定子と列指定子がリストで表示されます。

@も特殊項目指定子のひとつで、セルの中で使うと「このセルと同じ行の」という意味になります。この@はVBAでは使えません。

また、セルの中では"テーブル1[#すべて]"や"テーブル1[#データ]"のように日本語の特殊項目指定子を使用できますが、VBAで使うときは次のように英語で記述しなければなりません。

  • [#すべて] → [#All]
  • [#データ] → [#Data]
  • [#見出し] → [#Headers]
  • [#集計] → [#Totals]

見出しを含むテーブル全体

Range("テーブル1")

または

Range("テーブル1[#All]")

見出しを含まないテーブルのデータ全体

Range("テーブル1[#Data]")

イメージとしては、

  • [#All] → Rrange
  • [#Data] → DataBodyRange

のような感じです。[#All]は、タイトル行と集計行を含み、[#Data]はタイトル行と集計行を含みません

構造化参照で列を特定するときは、次のようにします。

Range("テーブル1[名前]")

上記のように、特殊項目指定子を省略して、列指定子だけを記述すると、[#Data]を指定したものとみなされます。

Range("テーブル1[[#All],[名前]]")

のように、[#All]を指定すると、タイトル行や集計行も含みます。

連続した複数の列を指定するときは、次のように書けます。

Range("テーブル1[[名前]:[記号]]")

ListObjectオブジェクトのListColumnでは、このような複数列をいきなり指定することはできません。VBAでは、コレクション内のメンバーに、1つずつしかアクセスできないからです。また、Range("テーブル1[[名前]:[記号]]")の書き方を応用して、非連続の[名前]列と[数値]列を指定することもできません。これは、構造化参照の制限でしょう。いずれにしても、両者を実現するには、Unionを使うのが早いです。

Sub Sample1()
    Dim Target As Range
    With Range("A1").ListObject
        Set Target = Union(.ListColumns(2).DataBodyRange, .ListColumns(3).DataBodyRange)
    End With
    Target.Select
End Sub

Sub Sample2()
    Dim Target As Range
    Set Target = Union(Range("テーブル1[名前]"), Range("テーブル1[数値]"))
    Target.Select
End Sub

構造化参照を使って、テーブル内の行を指定することはできません。テーブル内の行を操作したいときは、Range("テーブル1")方式の構造化参照ではなく、ListObjectオブジェクトを使います。