4

Excelのテーブル(ListObject)の特定の列が計算列であるかどうかをVBAでチェックインする方法はありますか(http://office.microsoft.com/en-us/excel-help/use-calculated-columns-のように) in-an-excel-table-HA010342380.aspx)?

計算列には、各行に同じR1C1数式が設定されるだけでなく、新しい行が追加されると自動拡張されることに注意してください(データ本体の範囲全体を削除してから、いくつかの新しい行を再作成すると、再入力されます)。したがって、一貫した数式を含む列をチェックすることは、計算された数式をチェックすることと同じではありません。

列を計算することも可能ですが、行の1つを他の数式または値で上書きし、自動拡張機能を保持することもできます。

したがって、これは列のプロパティである必要があるとかなり確信しています。VBAを介してどこにアクセスできるかわかりません。VBAオブジェクトモデルを介して公開されていない場合、この情報を取得するための回避策はありますか?

よろしくお願いします、カルロス

編集:Excel Office Open XMLファイルを掘り下げましたが、探しているのはxl \ Tables \ table*.xmlファイル<calculatedColumnFormula>の定義の要素であることがわかりました。<tableColumn>VBAを介してそれに到達する方法はありますか?

EDIT2:これは私が思いついたテストケースのサンプルファイルです。VBAは、列1、2、および3が計算列であり、列4および5は計算されていないことを通知する必要があります。

4

2 に答える 2

4

これは前に見たことがありませんが、次のように ListObject の列範囲のプロパティのようです。

Dim wks As Worksheet
Set wks = ActiveSheet
Dim li As ListObject
Set li = wks.ListObjects(1)
Dim col As ListColumn
Set col = li.ListColumns(2)    ' assuming column 2 of the table has a calculated formula
Dim r As Range
Set r = col.DataBodyRange
Let b = Not IsNull(r.FormulaArray)
if b then
    Let b = Len(r.FormulaArray) > 0 ' case where r.FormulaArray = "", suspect it's not a calculated column
End If
MsgBox b

IsNull(r.FormulaArray) の場合は計算列がありません。それ以外の場合はあります。

h番目


わかりました、これで少し遊んでみましたが、上記を使用して取得した範囲オブジェクトは、特定のセルの範囲オブジェクトとは異なることがわかりました。そのため、特定のセルがある場合は、対応する ListColumn の範囲を取得する必要があると思います.DataBodyRange 経由。

(たとえばSet r = r.Cells(1,1)、上記に挿入すると、IsNull(r.FormulaArray)テストは計算された列をテストするために機能しなくなりますが、代わりに、範囲に数式があるかどうかを示しますが、それは計算できるかどうかを示します。)

また、列が計算されると r.FormulaArray は文字列のように見えますが、そうでない場合 (計算列)、.FormulaArray は null を返します。これは有効な文字列値ではありません (これは、値をキャプチャするには、ブール値ではなくバリアントを使用する必要があります); IsNull(r.FormulaArray) は正常に動作しているようです。


既に計算された列の右側に列を追加すると、その新しく追加された列の r.FormulaArray = "" になります。セルの 1 つに値を入力すると、数式配列はすぐに予想される NULL に戻ります。そこで、私がこの偽陽性と考えるもののテストを追加しました。

于 2013-01-09T19:43:28.017 に答える
2

これはあなたの例に適切な答えを与えます。

残念ながら、状況によっては致命的な可能性のある欠点がいくつかあります。=RAND()1 つには、再計算が発生するため、サンプル内の数式を 介して生成された乱数が変更されます。

2 番目の欠点は、回答を取得するためにワークシートを変更することです (行った変更は削除されますが、それでも変更されます)。部分的にしか役に立たないいくつかの回避策を考えることができます: (a) この操作を必要に応じてほとんど実行せず、すべての列の結果をキャッシュし、(b) テーブルを新しいワークブックにコピーしてルーチンを実行します (そして新しいワークブックを削除します)。 . 後者は変更の欠点を回避しますが、元のワークブックの再計算をトリガーします (それ以外の場合は、独自の欠点があります)。それに加えて、テーブルを新しいワークブックにコピーすると、(ヘッダーだけでなく) 範囲全体をコピーしない限り、テーブル/ListObject が失われます。次に、4番目の列(計算に一貫性のない式)を計算された列に昇格させるようにも見えます。残念ながら、このプロモーションはシート全体をコピーするときにも発生します。

さて、FWIW:

Sub TestTable()
    Dim ans As String
    Let ans = ""

    Dim li As ListObject
    Set li = ActiveSheet.ListObjects(1)

    Dim rowCountBefore As Long
    Let rowCountBefore = li.ListRows.Count

    Dim lr As ListRow
    Set lr = Nothing

    On Error Resume Next
    Set lr = li.ListRows.Add(AlwaysInsert:=True)
    On Error GoTo 0

    Dim rowCountAfter As Long
    Let rowCountAfter = li.ListRows.Count

    If Not (lr Is Nothing) And rowCountAfter = rowCountBefore + 1 Then
        Dim c As Long
        For c = 1 To li.DataBodyRange.Columns.Count
            Dim b As Boolean
            Let b = lr.Range.Cells(1, c).HasFormula
            ans = ans & "col " & c & ": " & b & ";  "
        Next
        li.ListRows(rowCountAfter).Delete
    End If

    MsgBox ans
End Sub
于 2013-01-10T18:02:42.113 に答える