同步Excel表

时间:2018-11-01 09:55:55

标签: excel-vba

我在excel中有两个表,一个主表和一个数据表。 数据表包含某些需要在主数据库中更新的更新记录。我发现一个宏可以很好地完成此工作,除了在更新后,它会将表转换为范围并删除表。

在修改如何保留表但仍更新更改方面有帮助吗?

Source of the macro

代码:

Option Explicit

Sub NewNameandCostCenter()

Dim start As Double
start = Timer

Dim countOfChangedRows As Long

'set rngMap array
Dim rngMap As Range
Set rngMap = Worksheets("Map").Range("A1:D51")

'set rngData array
Dim rngData As Range
Set rngData = Worksheets("Data").Range("J2:M20001")

Dim aMap As Variant
aMap = rngMap.Value

Dim aData As Variant
aData = rngData.Value

Dim mapRow As Long
Dim datarow As Long
Dim mapcol As Long

For mapRow = LBound(aMap, 1) To UBound(aMap, 1)
For datarow = LBound(aData) To UBound(aData)
  'Check the key matches in both tables
  If aData(datarow, 1) = aMap(mapRow, 1) Then
    countOfChangedRows = countOfChangedRows + 1
    'Assumes the columns in map and data match
    For mapcol = LBound(aMap, 2) + 1 To UBound(aMap, 2)
      aData(datarow, mapcol) = aMap(mapRow, mapcol)
    Next mapcol
  End If
Next datarow
Next mapRow

rngData.Value = aData

Debug.Print countOfChangedRows & " of "; UBound(aData, 1) & " rows updated in " & Timer - start & " seconds"

End Sub

1 个答案:

答案 0 :(得分:0)

在工作簿的副本上尝试 快速编辑 。已对其进行编辑以直接在主表中进行更改,而不是将数据拉入数组然后粘贴回已编辑的副本。


说明

正在使用的现有代码有几个步骤:

  1. 将数据从范围拉入数组
  2. 比较数组并编辑aData(工作表数据中的数组)以匹配aMap(工作表Map中的数组)
  3. 将更新后的数组aData粘贴回它来自的范围

将数组数据粘贴回工作表范围时遇到的问题。可以通过直接在表中进行更改,而不是对要粘贴回的数组进行更改来解决此问题。

在VBA中,可以使用工作表的ListObjects集合以及所需Table对象的索引或名称来访问表对象。该列表对象具有各种有用的集合。 .ListRows.ListColumns.DataBodyRange等(我想可能还会有标头范围吗?)。对于大多数表,我发现.ListRows最有用。

ListRow(或ListColumn)的属性之一是其.Range功能。它需要一个行和一个列变量(类似于工作表中的.Cells)。在这种特殊情况下(代码循环遍历Tables ListRows集合-For each datarow in rngData.ListRows),数据行将只保留一行,因此row变量为常数1。column变量是相同的变量/从数组访问数据时使用的值。 (尽管我忘记了数组可能是从零开始的,所以我猜我们很幸运。)

ListRows和ListColumns集合的另一方面是.Count属性。我在一些地方使用了这个:

  1. mapcol分配适当的值范围以访问ListRows的每一列中的值
  2. 在代码末尾获取Debug.Print语句表中ListRows的总数

该代码可以通过.Range访问每个ListRow中的每个范围,因此代码能够:

  1. 将“地图”范围中的数据提取到数组中
  2. 将“映射”数组与主表进行比较,然后适当地编辑主表。

还可以重写代码,因此,无需将任何数据提取到数组中,而只是在一个表和下一个表之间进行直接比较(您可以在 Edited Code < / strong> )。


快速编辑

Option Explicit

Sub NewNameandCostCenter()

Dim start As Double
start = Timer

Dim countOfChangedRows As Long

'set rngMap array
Dim rngMap As Range
Set rngMap = Worksheets("Map").Range("A1:D51")

'set rngData table (previously set rngData array)
Dim rngData As ListObject
Set rngData = Worksheets("Data").ListObjects("TableName") 'Adjust to name of your master table

Dim aMap As Variant
aMap = rngMap.Value

Dim mapRow As Long
Dim datarow As ListRow 'For cycling through the table rows
Dim mapcol As Long

For mapRow = LBound(aMap, 1) To UBound(aMap, 1)
For each datarow in rngData.ListRows
  'Check the key matches in both tables
  If datarow.Range(1, 1) = aMap(mapRow, 1) Then
    countOfChangedRows = countOfChangedRows + 1
    'Assumes the columns in map and data match
    For mapcol = LBound(aMap, 2) + 1 To UBound(aMap, 2)
      datarow.Range(1, mapcol) = aMap(mapRow, mapcol)
    Next mapcol
  End If
Next datarow
Next mapRow

Debug.Print countOfChangedRows & " of "; rngData.ListRows.Count & " rows updated in " & Timer - start & " seconds"

End Sub

修改后的代码

Option Explicit

Sub NewNameandCostCenter()

Dim start As Double
start = Timer

Dim countOfChangedRows As Long

'set rngMap array
Dim rngMap As ListObject
Set rngMap = Worksheets("Map").ListObjects("TableName") 'Adjust to name of your data table

'set rngData table (previously set rngData array)
Dim rngData As ListObject
Set rngData = Worksheets("Data").ListObjects("TableName") 'Adjust to name of your master table

Dim mapRow As ListRow
Dim datarow As ListRow 'For cycling through the table rows
Dim mapcol As Long

For each mapRow in rngMap
For each datarow in rngData.ListRows
  'Check the key matches in both tables
  If datarow.Range(1, 1) = mapRow.Range(1, 1) Then
    countOfChangedRows = countOfChangedRows + 1
    'Assumes the columns in map and data match
    For mapcol = 2 To rngMap.ListColumns.Count
      datarow.Range(1, mapcol) = mapRow.Range(1, mapcol)
    Next mapcol
  End If
Next datarow
Next mapRow

Debug.Print countOfChangedRows & " of "; rngData.ListRows.Count & " rows updated in " & Timer - start & " seconds"

End Sub