Excel VBA: как проверить вычисляемый столбец?

Есть ли способ проверить в VBA, является ли определенный столбец таблицы (ListObject) в Excel вычисляемым столбцом (как в http://office.microsoft.com/en-us/excel-help/use-calculated-columns-in-an-excel-table-HA010342380.aspx)?

Обратите внимание, что вычисляемые столбцы не только будут иметь одинаковую формулу R1C1, установленную для каждой строки, но также будут автоматически расширяться при добавлении новых строк (они даже будут повторно заполняться, если вы удалите весь диапазон тела данных, а затем воссоздадите несколько новых строк). Таким образом, проверка столбцов с согласованными формулами - это не то же самое, что проверка вычисляемой формулы.

Возможно даже вычисление столбца, но при этом одна из строк будет перезаписана какой-либо другой формулой или значением, а функции автоматического расширения сохранятся.

Итак, я почти уверен, что это должно быть какое-то свойство столбца, я просто не уверен, где я могу получить к нему доступ через VBA. Если он не отображается через объектную модель VBA, есть ли способ получить эту информацию?

Заранее спасибо, Карлос

РЕДАКТИРОВАТЬ: Я немного покопался в файлах Excel Office Open XML, и оказалось, что я ищу элемент <calculatedColumnFormula> в определении <tableColumn> файлов xl \ tables \ table * .xml. Есть ли способ добраться до этого через VBA?

EDIT2: вот пример файла с тестовыми примерами, которые я мог придумать. VBA должен сигнализировать, что столбцы 1, 2 и 3 являются вычисляемыми столбцами, а столбцы 4 и 5 - нет.


person user1139216    schedule 09.01.2013    source источник
comment
Взгляните на stackoverflow.com/questions/13753563/ - у меня была аналогичная проблема. Насколько мне известно, в XML нет эквивалента VBA свойству <calculatedColumnFormula>. :-(   -  person Peter Albert    schedule 10.01.2013
comment
Вот чего я боюсь ...   -  person user1139216    schedule 10.01.2013


Ответы (2)


Это дает подходящие ответы для вашего примера.

К сожалению, у него есть несколько потенциально фатальных недостатков, в зависимости от ситуации. Во-первых, это вызывает повторный расчет, поэтому случайные числа, сгенерированные с помощью =RAND() формул в вашем примере, изменяются.

Второй недостаток заключается в том, что он изменяет рабочий лист, чтобы получить ответы (он удаляет внесенные изменения, но все же изменяется). Я могу придумать несколько лишь частично полезных обходных путей: (а) выполняйте эту операцию настолько редко, насколько это необходимо, и кешируйте результаты для всех столбцов, и (б) скопируйте таблицу в новую книгу и запустите процедуру (и удалите новую книгу) . Хотя последний позволит избежать недостатка модификации, он по-прежнему вызывает повторный расчет для исходной книги (и в остальном имеет свои недостатки). Чтобы добавить к этому, копирование таблицы в новую книгу теряет table / 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
person Erik Eidt    schedule 10.01.2013
comment
Спасибо за хорошую работу, Эрик. Я надеялся на более элегантное решение, но теперь убежден, что это будет настолько хорошо, насколько возможно. - person user1139216; 11.01.2013

Я не смотрел на это раньше, но похоже, что это свойство диапазона столбцов 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), то у него нет вычисляемого столбца, в противном случае он есть.

hth


Хорошо, поиграем с этим немного, и я вижу, что объект диапазона, полученный с помощью приведенного выше, отличается от объекта диапазона для любой данной ячейки, поэтому, если у вас есть данная ячейка, я думаю, вам нужно будет получить соответствующий диапазон ListColumn через .DataBodyRange.

(Например, если вы вставите Set r = r.Cells(1,1) в указанное выше, тогда тест IsNull(r.FormulaArray) больше не работает для проверки вычисляемого столбца, а вместо этого просто говорит, есть ли в диапазоне формула, но ее можно вычислить или нет.)

Кроме того, в то время как r.FormulaArray кажется строкой при вычислении столбца, если это не так (вычисляемый столбец), то .FormulaArray возвращает null, что не является допустимым строковым значением (что затрудняет использование в что для захвата значения вы должны использовать вариант, а не логическое значение); Я обнаружил, что IsNull (r.FormulaArray), похоже, работает нормально.


Если я добавлю столбец справа от уже рассчитанного столбца, тогда r.FormulaArray = "" для этого нового добавленного столбца. Если вы поместите значение в одну из его ячеек, массив формул немедленно вернется к более ожидаемому NULL. Итак, я добавил тест на то, что считаю ложноположительным.

person Erik Eidt    schedule 09.01.2013
comment
Ваш код фактически проверяет согласованность формул в таблице, которая отличается от вычисляемых столбцов. У меня сейчас нет доступа к каким-либо службам хранения, но как только я получу, я прикреплю к этому вопросу файл Excel, показывающий, где происходит сбой кода, и содержащий тестовые примеры, которым должно соответствовать решение. - person user1139216; 10.01.2013
comment
В порядке. Я использую Excel 2010, и этот код, по-видимому, эффективно различает столбец, который вычисляется (как описано в статье, которую вы цитируете), и столбец, в котором либо столбец со всеми согласованными формулами, либо одна несогласованная формула (зеленый треугольник), либо просто значения . Я нашел один пример, в котором он давал ложное срабатывание, поэтому добавил, чтобы проверить это. - person Erik Eidt; 10.01.2013
comment
В моем тестовом примере я получаю поведение расширения таблицы, как описано в статье, и оно коррелирует с результатами вышеизложенного (вычисляемые столбцы - это те, формула которых автоматически заполняется, когда таблица расширяется строкой, а невычисленные - нет; приведенный выше код дает истину для первого набора и ложь для второго набора). - person Erik Eidt; 10.01.2013
comment
Я разместил пример по исходному вопросу. Как видите, ваш код выдает два ложных отрицания для столбцов 2 и 3 и ложное срабатывание для столбца 4 (просто разверните таблицу на одну строку вниз, и вы поймете, что я имею в виду). - person user1139216; 10.01.2013