Excel VBA: как найти первую пустую строку в таблице для процедуры цикла?

#vba #excel #loops

#vba #excel #циклы

Вопрос:

Я переформатировал диапазон Sheets("Records") в рабочей книге как a Table (named "RecordsTable") , чтобы упростить выполнение INDEX(MATCH,MATCH) функций для создания отчетов…. но теперь я испортил свою процедуру цикла для заполнения этого диапазона с момента ввода Sheets("FORM") .

Раньше это было:

 Set r = Sheets("Records").Range(A amp; Rows.Count).End(x1Up).Offset(1, 0)

i = 0

   For Each c In Range("dataRange")              
   'dataRange is a list of cells to reference from the FORM input sheet

   r.Offset(0, i).Value = Worksheets("FORM").Range(c)
   i = i   1
Next
  

Однако этот код теперь выбирает первую строку в КОНЦЕ "RecordsTable" (строка 501, поскольку я определил 500 строк в моей таблице) и вставляет туда данные.

Я попытался изменить его на это:

 Set r = Sheets("Records").ListObjects("RecordsTable").DataBodyRange("A" amp; Rows.Count).End(x1Up).Offset(1, 0)

i = 0

   For Each c In Range("dataRange")              

   r.Offset(0, i).Value = Worksheets("FORM").Range(c)
   i = i   1
Next
  

Но этот код по-прежнему выбирает строку 501 и делает эту строку частью "RecordsTable" .
Как я могу правильно Set "r" to = использовать первую пустую строку в "RecordsTable" ?

Для справки, Column "A" in "RecordsTable" имеет заголовок [INV #] . Кроме того, когда я перехожу в "Set r = ..." строку, Rows.Count возвращается значение более 1 миллиона (т. Е. Общее количество строк на листе) — если я правильно понимаю, я хочу, чтобы оно возвращало значение 500 (т. Е. Общее количество строк в таблице) — это правильно?

Редактировать

"dataRange" это список ссылок на ячейки с одним столбцом (у меня они помечены в столбце B, как предлагает @chrisneilsen:

A

J6

Y6

J8

J10

Y8

и т.д.

Это ячейки Sheets("FORM") , из которых мне нужно извлекать данные и заполнять их в моей таблице в порядке, указанном в "dataRange" .

Комментарии:

1. Очень быстрое предложение: посмотрите, как вы разместили рабочий лист перед использованием ListObjects ? Делайте это каждый раз, когда вы используете Range() , Cells() , и т.д. Rows.Count Это подскажет VBA, с какого листа получать эту информацию. В противном случае он использует ActiveSheet , и это может привести к неожиданным результатам.

2. @BruceWayne ^^ Спасибо

Ответ №1:

Предполагая, что у вас действительно есть таблица, добавьте данные в таблицу (ListObject), используя ее свойства и методы:

 Sub Demo()
    Dim lo As ListObject
    Dim c As Range

    Set lo = Worksheets("Records").ListObjects("RecordsTable")

    For Each c In Sheets("V").Range("dataRange")
        If Not lo.InsertRowRange Is Nothing Then
            lo.InsertRowRange.Cells(1, 1) = Sheets("FORM").Range(c)
        Else
            lo.ListRows.Add.Range.Cells(1, 1) = Sheets("FORM").Range(c)
        End If
    Next
End Sub
  

Примечание: зацикливание диапазона на листе V и использование его в качестве указателя на данные на листе FORM , скопированные из вашего ответа — я предполагаю, что вы знаете, что вы здесь делаете

На основе комментария OP, добавление данных в одну новую строку

 Sub Demo()
    Dim lo As ListObject
    Dim c As Range, TableRange As Range
    Dim i As Long

    Set lo = Worksheetsheets("Records").ListObjects("RecordsTable")

    If Not lo.InsertRowRange Is Nothing Then
        Set TableRange = lo.InsertRowRange
    Else
        Set TableRange = lo.ListRows.Add.Range
    End If
    i = 1
    For Each c In Sheets("V").Range("dataRange")
        TableRange.Cells(1, i) = Sheets("FORM").Range(c)
        i = i   1
    Next
End Sub
  

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

Как упоминалось в обновленном OP, если метки столбцов находятся в следующем столбце, замените For цикл этим (и добавьте Dim r as Range, col as long в объявления)

     For Each c In Sheets("V").Range("dataRange")
        If Not c = vbNullString Then
            Set r = Worksheets("FORM").Range(c.Value)
            col = lo.ListColumns(c.Offset(, 1).Value).Index
            TableRange.Cells(1, col) = r.Value
        End If
    Next
  

Комментарии:

1. Спасибо. Я попытался использовать это, и он правильно добавляет строку в таблицу и начинает ввод данных в первом столбце, но последующие итерации продолжают добавлять данные в первый столбец, следующую доступную строку. У меня определено 40 ячеек dataRange , и мне нужно, чтобы каждая из них переходила в следующий столбец после предыдущего.

2. Хорошо, это новая информация. Итак, вы хотите добавить только одну новую строку и вставить все данные в эту строку? См . Обновление

3. Спасибо, Крис. Я пытался решить это с тех пор, как вы опубликовали, и это обновление помогает. Тем не менее, он по-прежнему выдает мне «ошибку, определяемую приложением или объектом» TableRange.Cells(1, i) = Sheets("FORM").Range(c) .

4. Основываясь на вашем коде = Sheets("FORM").Range(c) , я предполагаю dataRange , что это список адресов на листе FROM . Это правильно? Если значение c не является допустимым адресом (например C10') that will cause an error. can you post (edit your Q) some sample data for both , recordsTable` и dataRange

5. Вопрос обновлен, как и было запрошено. Надеюсь, это то, что вы искали.