【问题标题】:Click Button Excel 2013 Copy rows from one excel table to another based on cell value单击按钮 Excel 2013 根据单元格值将行从一个 Excel 表复制到另一个
【发布时间】:2015-06-23 09:35:01
【问题描述】:

我对 VBA 很陌生,一直在努力寻找任何现有的信息:

我有一个工作簿(excel 2013),其中包含一个包含数据/文本等的表格(excel 表格),如主项目列表。在其他几张纸上,我有类似数据的类似表格,但用于子项目。我想要做的是在主页上有一个带有主项目列表(第一张表)的点击按钮,一旦点击,它将检查其他表(子项目)上的表格,以查看第 1 列中为“是”的行和将每一行(带有是)复制到主项目表中的下一个可用行。必须检查第 2 列中的唯一引用,以免重复行。

我已经开始使用我在这里找到的一些代码,但它是用于复制到新工作表,而不是表格,并且显然只是我尝试实现的功能的一部分。

Sub Button2_Click()
Dim r As Long, endRow As Long, pasteRowIndex As Long

endRow = 10
pasteRowIndex = 1

For r = 1 To endRow

    If Cells(r, Columns("B").Column).Value = "yes" Then
    Rows(r).Select
    Selection.Copy

    'Switch to the sheet where you want to paste it & paste
    Sheets("Sheet2").Select
    Rows(pasteRowIndex).Select
    ActiveSheet.Paste

    'Next time you find a match, it will be pasted in a new row
    pasteRowIndex = pasteRowIndex + 1


    'Switch back to your table & continue to search for your criteria
    Sheets("Sheet1").Select
    End If
Next r
End Sub

对此的任何帮助将不胜感激。

【问题讨论】:

  • 如果使用表格,你查过表格符号吗?试试宏记录器看看如何与之交互怎么样?

标签: vba excel


【解决方案1】:

这里有两件主要的事情需要考虑:

  1. 如何将一行从一个表添加到另一个表?
  2. 如何判断该行是否已经存在于表中?

向表中添加新行

表格可以为您节省一些工作,因为您不必找到最后一行。要从 Range 对象向表中添加新行,您可以按照以下示例函数的方式执行操作。

' Inserts a row to the table from a range object.
Private Function InsertTableRowFromRange(table As ListObject, source As Range)

  Dim newRow As ListRow

  Set newRow = table.ListRows.Add(AlwaysInsert:=True)
  newRow.Range(1, 1).Resize(source.Rows.Count, source.Columns.Count) _
        .Value = source.Value

End Function

然后您可以遍历其他表中的行并插入符合要求的范围。

' Inserts toggled rows from the source table to the target table.
Private Function InsertToggledRows(source As ListObject, target As ListObject)

  Dim row As ListRow

  For Each row In source.ListRows
    If row.Range(1, 1).Value = "yes" Then
      InsertTableRowFromRange target, row.Range
    End If
  Next

End Function

重复的呢?

有很多方法可以使用 VBA 处理重复项 - 您可能还需要考虑一些不同的场景。例如,考虑以下情况:

索引为 8 的项在两个不同的表中设置为yes,并且在每个表中具有不同的名称。应该使用哪个表?当一个项目在一个表中设置为 yes 而在另一个表中设置为 no 时会怎样?


对于上面屏幕截图中的结果,我将主表中的索引添加到 array 并使用 this answer 中的函数将潜在的新索引与数组中的索引进行比较。

InsertToggledRows 也需要进行一些更改,因为它现在还必须更新 indexes 数组。我在以下示例中采用的路径涉及一些尴尬的返回值,并且不是唯一的做事方式。

示例设置

Option Explicit

' Inserts toggled rows with unique identifiers from other tables to the master.
Public Sub InsertTablesToMasterTable()

  Application.ScreenUpdating = False

  Dim ws As Worksheet
  Dim masterTable As ListObject
  Dim firstTable As ListObject
  Dim secondTable As ListObject
  Dim indexes() As Variant

  Set ws = ThisWorkbook.Worksheets(1)
  ' Set your table objects to variables
  With ws
    Set masterTable = .ListObjects("Master")
    Set firstTable = .ListObjects("Table1")
    Set secondTable = .ListObjects("Table2")
  End With

  ' Get the indexes from the existing table
  indexes = GetInitialIndexes(masterTable)

  ' Insert the rows & update the indexes array
  indexes = InsertUniqueToggledRows(firstTable, masterTable, indexes)
  indexes = InsertUniqueToggledRows(secondTable, masterTable, indexes)

  Application.ScreenUpdating = True

End Sub

' Returns an array of the initial indexes found in the table.
Private Function GetInitialIndexes(table As ListObject) As Variant

  Dim arr() As Variant
  ReDim arr(0 To table.ListRows.Count)
  Dim row As ListRow
  Dim i As Integer

  i = 0
  For Each row In table.ListRows
    arr(i) = row.Range(1, 2).Value
    i = i + 1
  Next

  GetInitialIndexes = arr

End Function

' Inserts toggled rows from the source table to the target table and returns
' an array which has the new indexes appended to the existing array.
Private Function InsertUniqueToggledRows( _
                                          source As ListObject, _
                                          target As ListObject, _
                                          indexes As Variant _
                                        ) As Variant

  Dim arr() As Variant
  Dim row As ListRow

  arr = indexes

  For Each row In source.ListRows
    If row.Range(1, 1).Value = "yes" And _
    Not IsInArray(row.Range(1, 2).Value, indexes) Then
      InsertTableRowFromRange target, row.Range

      ' Push the new index to the array
      ReDim Preserve arr(0 To UBound(arr) + 1) As Variant
      arr(UBound(arr)) = row.Range(1, 2).Value
    End If
  Next

  InsertUniqueToggledRows = arr

End Function

' Inserts a row to the table from a range object.
Private Function InsertTableRowFromRange(table As ListObject, source As Range)

  Dim newRow As ListRow

  Set newRow = table.ListRows.Add(AlwaysInsert:=True)
  newRow.Range(1, 1).Resize(source.Rows.Count, source.Columns.Count) _
        .Value = source.Value

End Function

' Returns true if the string is found in the array.
Private Function IsInArray(stringToFind As String, arr As Variant) As Boolean
  IsInArray = (UBound(Filter(arr, stringToFind)) > -1)
End Function

【讨论】:

  • 太好了,谢谢!它完全按照我的意图工作。只是一个简单的问题,如果表格在不同的工作表上,需要更改什么?
  • 唯一应该改变的是变量定义本身。在示例中,所有三个表都设置在 With ws 块中 - 您也可以将每个表设置为不同的工作表。
  • 谢谢,效果很好。我遇到的一个小问题是更新公式。每个表中的最后一列(复制到和复制)是计算值。添加新行后,它仅作为文本/值,我如何让它保留公式,或在复制后自动填充现有公式?
  • 请避免提出与 cmets 中的原始问题没有直接关系的问题。如果找不到所需的内容,您可以尝试四处寻找或提出新问题。话虽如此 - 原因是因为代码正在复制 Value 而不是 Formula。在InsertTableRowFromRange 函数中,newRow.Value 设置为source.Value。如果您想复制公式,请将两者都替换为 .Formula
猜你喜欢
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多