【问题标题】:Trouble with VBA to transfer data from multiple workbooks to master workbookVBA 无法将数据从多个工作簿传输到主工作簿
【发布时间】:2016-10-01 10:10:10
【问题描述】:

我正在使用 Excel 2013 并尝试使用教程 Transfer to Master from Multiple Workbooks 中的以下代码将数据从多个工作簿传输到主工作簿。它将来自多个 wkbk 的数据添加到主 wkbk 中,每次都将数据粘贴在其上方数据的下方,而不是在主 wkbk 中的单独电子表格上。

我按照教程将代码放入 MASTER 工作簿,但没有任何反应。我不太了解VBA。我刚刚学会了如何中断并运行代码,但这并不能真正告诉我任何事情,我不认为。

  1. 我的桌面上有一个名为“merge”的文件夹,其中启用了一个名为 MASTER 的宏 wkbk,另外 3 个非宏 wkbk 名为 tblScheduleMergeTWO、tblScheduleMergeTHREE 和 tblScheduleMergeFOUR。
  2. 每个 wkbk,包括 MASTER,都有 9 列具有相同的字段标题,我认为这与此代码无关。
  3. 我需要从中复制的 3 个 wkbk 在数据上具有不同的阴影,因此当它粘贴到 MASTER 时,我可以知道哪些数据来自哪个 wkbk。

我的尝试:海报编辑 -

  1. 我打开 MASTER wkbk 并将光标放在该 wkbk 中并从那里运行代码。

  2. 我已尝试使用需要从打开复制的其他 wkbks 之一,并尝试关闭它,屏幕有时会闪烁一次,但在复制任何数据方面没有任何反应。

  3. 根据@Tony Dallimore 的建议,在ActiveSheet.Paste Destination:Loop Application.DisplayAlerts = True 之后移动了Active.Workbook.Close,它并没有改变任何东西。我不确定它是否会删除任何关闭 wkbk 的内容,但他会知道得更好。

  4. 根据 #Tony Dallimore 的建议,分别将 Cells(erow, 9) 更改为 Cells(erow, lastcolumn),并与其他编辑一起进行,但没有任何变化。

  5. 不理解#Tony Dallimore 的第三个建议。是要替换Range(Cells(2, 1), Cells(lastrow, lastcolumn)).Copy withSrcRange.Copy Destination:=DestTopLeftCell?我没有看到它会覆盖 lastrow 到 lastcolumn。`

  6. 我还尝试了另一个教程,但它在 enter link description here 中也不起作用。没有发布代码以节省空间。

10/1/19 11:19 AM 海报编辑 10. 根据@Thomas Inzina 的建议,我在他发布的代码中使用 F8 逐行排除故障。当您单击 ThisWorkbook 或单击 Sheet1 时,我立即注意到使用 F8 时,代码的开头行“With ThisWorkbook.Worksheets("Sheet1")' 在屏幕提示中显示为 FileName=""。它看起来甚至不识别 ThisWorkbook,它实际上被称为 MASTER.xlsm。那是怎么回事?但是,当您将光标悬停在“Do While FileName ""' 上时,屏幕提示会显示文件名。然后当我按 F8 时,它会弹出一个消息,说您的 MASTER 文件已经打开并且可能会损坏重新打开。当我选择“否”时,我不想再次打开它,我收到一条错误消息,询问我是要结束还是调试。如果我调试,则“With Workbooks.Open(FolderPath & FileName)”突出显示为问题。我只需要保存并关闭Master wkbk,然后那个麻烦就消失了;但是,在“With Workbooks.Open(FolderPath & FileName)”之后按 F8 会跳过其余代码并返回到开头。在所有这些中,我没有看到代码给出了一个屏幕提示,表明它注意到了我需要从中复制的 wkbks。

我将不胜感激。我也要去看看这个帖子Other post to t/f data from multiple wkbks

可能是 FileName = Dir 错了吗?

Sub copyDataFromMultipleWorkbooksIntoMaster()

Dim FolderPath As String
Dim FilePath As String
Dim FileName As String
'or Dim FolderPath As String, FilePath As String, FileName As String

FolderPath = "C:\Users\PC-1\Desktop\Merge\"
FilePath = FolderPath & "*.xls*"
FileName = Dir(FilePath)

'Don't know how many rows of data so define last row and column
Dim lastrow As Long
Dim lastcolumn As Long
'will use in a loop as number columns and rows from which extract data

Do While FileName <> ""
Workbooks.Open (FolderPath & FileName)

'Assign value to last row
lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlLeft).Column

Range(Cells(2, 1), Cells(lastrow, lastcolumn)).Copy
Application.DisplayAlerts = False
'to disable alerts that you have a lot of data copied to clipboard, etc.
Active.Workbook.Close

'when go back to master to paste, we need to know which is next blank row to paste data
erow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
'Offset to go to next row
ActiveSheet.Paste Destination:=Worksheets("Sheet1").Range(Cells(erow, 1), Cells(erow, 9))

FileName = Dir

Loop
Application.DisplayAlerts = True



End Sub

10/2/2016 海报编辑 - 回应 Tony Dallimore - 托尼,我通读了代码,但认为我理解的足够多,可以运行它并看看会发生什么(但是,我将更深入地研究它并重新输入它);但是,当我尝试运行它时,什么也没发生。我是否应该将我的工作簿名称或任何工作表名称(例如:WshtDestName)替换为代码?

我收到一个运行时错误 9 下标超出范围错误,当我调试它时,Set WshtDest = WbkDest.Worksheets(WshtDestName) 被突出显示。

我想我应该用我的 MASTER.xlsm 文件中的 wksht 名称替换上面的 WshtDestName。所以,我把“Sheet1”放在括号里。没有错误消息,但也没有发生任何事情。

我想也许我要在两个常量Const WshtDestName As String = "Data"Const WshtSrcName As String = "Data" 中用我的 wksht 名称替换两个 wkbks 中的“数据”,所以我将“Sheet1”放在“数据”所在的位置,然后,再次,什么也没发生。

我不知道开头的常量是否应该在 Sub 之后,所以我将它们移动到 Dim 之后的 Sub 之后,然后什么也没发生。

当我按 F8 查看每一行代码时,屏幕提示如下:

  • 对于 Application.ScreenUpdating = False 它说 Application.ScreenUpdating = True

  • 对于 Set WbkDest = ThisWorkbook,屏幕提示显示 WbkSet = Nothing 和 ThisWorkbook = ,但仅在黄色突出显示时才显示这些内容。当按下 F8 并移出那条线时,当我将光标放在它上面时它什么也没说。

  • 对于 Set WshtDest = WbkDest.Worksheets(WshtDestName),屏幕提示显示 WshtDest = Nothing,对于 WbkDest.Worksheets(WshtDestName) = 下标超出范围,如果光标刚刚超过 (WshtDestName),则显示 ( “数据”),但仅在黄色突出显示时才显示这些内容。当按下 F8 并移出那条线时,当我将光标放在它上面时它什么也没说。

  • 除非我将 ("Data") 更改为 ("Sheet1"),否则我无法通过 F8。我可以在屏幕提示中 F8 到 FolderPath = WbkDest.Path & "\" = "C:\Users|PC-1\Destktop\Merge\" WbkDest.Path = "C:\Users|PC-1\Destktop\合并”,这是正确的。

  • FilePath = FolderPath & ".xls" = "C:\Users|PC-1\Destktop\Merge\".xls*" 在屏幕提示中 FolderPath 正确为上面,“C:\Users|PC-1\Destktop\Merge\”

  • FileName = Dir$(FilePath) = "MASTER.xlsm" 在屏幕提示中,FilePath 等于 "C:\Users|PC-1\Destktop\Merge*.xls*",如上。

  • Set RngDest = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious) 其中 RngDest = 提示中没有任何内容,屏幕提示中除了 -4123 之外没有任何内容弹出xlFormulas,1 代表 xlByRows,2 代表 xlPrevious。

  • 如果 RngDest 没有,那么其中 RngDest = 提示中没有任何内容

  • HeaderCopied = False = HeaderCopied = False in tip which is not true b/c my destination wkbk, MASTER.xlsm 在第一行已有标题行。

  • RowDestNext = 1 = RowDestNext = 1 在屏幕提示中

  • 然后跳转到 EndIf 和 EndWith

  • Do While FileName "" And FileName WbkDest.Name 在屏幕提示中 FileName 和 WbkDest.Name = "MASTER.xlsm"。

  • F8 然后跳转到代码的其余部分到末尾

    使用 WshtDest .Cells.EntireColumn.AutoFit 以等结尾。

我也按照您键入的方式运行了您的代码,除了我注释掉了您说要注释掉的部分(如果我确实有标题),并且我取消了注释您说要取消注释的部分。还是不行。

【问题讨论】:

  • (1) 在 Excel 中,如果您复制一个范围,则在粘贴该范围之前只允许执行有限数量的操作。您可以移动光标或切换工作簿,但例如,如果您修改另一个单元格,则副本会丢失。您正在复制范围,然后在尝试粘贴之前关闭源工作簿。在关闭之前尝试粘贴。 (2) 请与您的栏目保持一致。您正在阅读 1 到最后一列,但将 1 粘贴到 9。 (3) 复制然后粘贴模拟 Excel。 SrcRange.Copy Destination:=DestTopLeftCell 是 VBA 等效项。
  • #Tony Dallimore,我在原始帖子中添加了我的响应/cmets,以便我可以作为代码发布。我试过你的建议,除了最后一 (3) 个 b/c 我不明白该怎么做。他们没有改变问题——它什么也没做,只是像做了什么一样闪烁。你有什么其他的建议?感谢您的帮助。
  • 不要在用户名前使用#,因为它没有任何作用。如果您使用@,指定的人将在他们的收件箱中收到一条消息,告诉他们该消息。请注意,我没有包含 @ 和您的用户名,因为这是您的问题,并且您会被自动告知任何 cmets,同样,您无需在针对我的答案的评论中包含我的姓名,因为我会自动被告知它。
  • @Tony Dallimore - 谢谢你,托尼。是的,我会将两者都放在 b/c 中,我不确定,而且我担心如果另一个人也应该回答,其他人不会知道我在和谁说话。感谢您的澄清。

标签: excel pasting vba


【解决方案1】:

我已经设置了一个与您的描述相匹配的文件夹和工作簿。下面修改后的代码对我有用。我希望原始代码是你的。我可以很容易地原谅新手的一些错误和不良做法,但如果你按照你的建议从教程中得到这个,我会感到震惊。

我已包含 cmets 来解释我的所有更改。如有必要,请回来寻求更多解释,但你自己破译我的代码越多,你发展技能的速度就越快。我包括 cmets 来说明代码在做什么,但很少有 cmets 关于语句本身。例如,Option Explicit 一旦知道它存在就很容易查找,因此不解释其用途。

Option Explicit         ' Always have this statement at the top of every module

  ' Constants are fixed while a macro is running but can be changed
  ' if the data is redesigned. This defines the first data row of every
  ' worksheet is 2. That is, it allows for one header row. I could have used
  ' 2 within the code below. If you ever have to update code because the
  ' number of header rows has changed or a new column has been inserted in
  ' the middle of existing columns, you will understand why I use constants.
  Const RowDataFirst As Long = 2        ' Set to 1 if no header rows

  ' You assume that when you open a workbook, the active worksheet is the one
  ' required. This is only reliable if the workbooks only have one worksheet.
  ' I have defined one constant for the name of the worksheet within the
  ' destination workbook and one for name of the worksheet within every
  ' source workbook. I assume this is adequate. I will have alternative
  ' suggestions if it is not adequate.
  Const WshtDestName As String = "Data"
  Const WshtSrcName As String = "Data"
Sub copyDataFromMultipleWorkbooksIntoMaster()

  Dim FolderPath As String
  Dim FilePath As String
  Dim FileName As String
  Dim HeaderCopied As Boolean
  Dim RowDestNext As Long
  Dim RngDest As Range
  Dim RngSrc As Range
  Dim WbkDest As Workbook
  Dim WbkSrc As Workbook
  Dim WshtDest As Worksheet
  Dim WshtSrc As Worksheet

  Application.ScreenUpdating = False

  ' You need row numbers in both the source and the destination worksheets.
  ' Use names for variables that tell you exactly what the variable is for.
  ' While you are writing a macro, it is easy to remember odd names but if
  ' you return to the macro in six or twelve months will you still remember?
  ' I have a naming system which I always use. I can look at macros I wrote
  ' ten years ago and know what all the variable are which is an enormous help
  ' when updating old code. If you do not like my system then develop your own.
  ' My names consist of a series of keywords with the most global first.
  ' "Row" says the variable is a row number. "Wbk" says the variable is a
  ' workbook. "RowXxx" says the variable is a row number within worksheet or
  ' array Xxxx. "RowSrcXxx" says the variable is a row number for worksheet
  ' "Source". "Xxx" can be "First", "Crnt", "Next", Prev", "Last" or whatever
  ' I need for the current macro

  Dim RowSrcLast As Long

  ' My comment suggested you be consistent in your use of column numbers but
  ' comments do not allow enough room to explain. With some statements, having
  ' a different number of rows or columns in the source and destination can
  ' give funny results with truncation or duplication. If you know you only
  ' want 9 columns then use 9 in both source and destination ranges. If the
  ' number of columns might change then determine the number at runtime.
  Dim ColSrcLast As Long

  ' If you are handling multiple workbooks be explicit which workbook
  ' you are addressing.  This assumes the workbook into which the worksheets
  ' are collected is the workbook containing the macro.
  Set WbkDest = ThisWorkbook

  Set WshtDest = WbkDest.Worksheets(WshtDestName)
  ' Note a worksheet variable references the worksheet within its workbook.
  ' I do not need to write WbkDest.WshtDest.

  ' FolderPath = "C:\Users\PC-1\Desktop\Merge\"
  ' You can hard code the name of the folder into a macro but it is
  ' a bother when you move your workbooks. When all your workbooks
  ' are in the same folder, the following is more convenient
  FolderPath = WbkDest.Path & "\"

  FilePath = FolderPath & "*.xls*"

  ' Note Dir searches down the folder index for files that match the template.
  ' The sequence in which they are found depends on the sequence in which the
  ' files were added to the folder. There are other techniques if sequence is
  ' important.
  FileName = Dir$(FilePath)         ' Dir$ is marginally faster than Dir

  ' Your existing code adds new data to the end of the existing worksheet in
  ' Master.xlsm. This may be correct but it is more usual to clear the
  ' destination at the start of each run. Comment out the first block and uncomment
  ' the second block if you want to add to existing data.

  With WshtDest
    .Cells.EntireRow.Delete  ' Delete every row in worksheet
    HeaderCopied = False     ' There is no header within the destination worksheet
    RowDestNext = 1          ' First (only) header row will be copied from first
                             ' source worksheet to this row
  End With

  ' If you know that column A of the used rows of the active sheet contains no
  ' blank cells, the following is the easiest way of finding that last used row:
  '   RowDestLast = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
  ' But this technique is unreliable if there might be blank cells. No technique
  ' is 100% reliable but you would have very strange data if the technique I have
  ' used is not reliable for you.

  'With WshtDest
  '  ' Find last row with a value
  '  Set RngDest = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious)
  '  If RngDest Is Nothing Then
  '    ' No data has been found so the worksheet is empty
  '    HeaderCopied = False     ' There is no header within the destination worksheet
  '    RowDestNext = 1          ' First (only) header row will be copied from first
  '                             ' source worksheet to this row
  '  Else
  '    ' There is data within the worksheet. Assume the header row(s) are present.
  '    HeaderCopied = True
  '    RowDestNext = RngDest.Row + 1
  '  End If
  'End With

  ' Please indent your code within Do-Loops, If, etc. It makes your code
  ' much easier to read.

  ' All your workbooks are within the same folder. Master.xlsm will be one
  ' of those found but you do not want to use it as a source workbook.

  Do While FileName <> ""
    If FileName <> WbkDest.Name Then
      Set WbkSrc = Workbooks.Open(FolderPath & FileName)

      ' WbkSrc will be the active workbook but better to reference it explicitly

      With WbkSrc
        Set WshtSrc = .Worksheets(WshtSrcName)
      End With

      With WshtSrc
        ' Find last row with data if any
        Set RngSrc = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious)
        If RngSrc Is Nothing Then
          ' No data has been found so the worksheet is empty
        Else
          RowSrcLast = RngSrc.Row
          ' Find last column with data. Already know there is data
          RngSrc = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByColumns, xlPrevious)
          ColSrcLast = RngSrc.Column

          If HeaderCopied Then
            ' Already have header row(s) in destination worksheet
            Set RngSrc = .Range(.Cells(RowDataFirst, 1), .Cells(RowSrcLast, ColSrcLast))
          Else
            ' Do not have header row(s) in destination worksheet. Include them in copy.
            Set RngSrc = .Range(.Cells(1, 1), .Cells(RowSrcLast, ColSrcLast))
            HeaderCopied = True
          End If
          RngSrc.Copy Destination:=WshtDest.Cells(RowDestNext, 1)  ' Copy data and formats
          RowDestNext = RowDestNext + RngSrc.Rows.Count            ' Step ready for next copy
        End If
      End With  ' WshtSrc

      WbkSrc.Close SaveChanges:=False
      Set WshtSrc = Nothing
      Set WbkSrc = Nothing

    End If  ' FileName <> WbkDest.Name

    FileName = Dir$

  Loop  ' While FileName <> "" And FileName <> WbkDest.Name

  With WshtDest
    .Cells.EntireColumn.AutoFit
  End With

  Application.ScreenUpdating = True

End Sub

针对原始答案的 OP 的 cmets 的新部分

有些东西我真的应该包含在我的原始答案中,但你也误入了我无法预料的领域。您还发现了一个我自己的测试遗漏的错误。

“我应该用我的工作簿名称替换任何东西吗……”

我应该说清楚的。在Const WshtDestName As String = "Data" 中,“数据”是我在其中积累数据的工作表的名称。我应该告诉你在工作表中用你的名字替换“数据”。

您的 cmets 建议您已更换:

 Set WshtDest = WbkDest.Worksheets(WshtDestName)

 Set WshtDest = WbkDest.Worksheets("Sheet1")

如果是这样,请改为更新 Const 语句。使用Const 语句的目的是隔离代码主体中可能发生变化的内容。这使维护更容易。

避免使用默认名称“Sheet1”、“Sheet2”等。随着您的数据和宏变得越来越复杂,如果工作表名称反映了工作表的内容,事情就会变得更加轻松。

[来自 OP 的注释:我将我的主 wksht 重命名为“Combined”,将源的 wkshts 重命名为“Node Export By Hub”,并将常量中的“Sheet1”名称替换为这些名称。 ]

我使用WbkDest.Name 作为主工作簿的名称。您无需将其更改为您的实际工作簿名称。使用这样的属性使您的代码更易于维护,因为如果您重命名工作簿,属性值将会更改。

我收到一个运行时错误 9 下标超出范围错误,当我调试它时,Set WshtDest = WbkDest.Worksheets(WshtDestName) 被突出显示。

本段可能超出您目前对 VBA 的了解。阅读并提取你能理解的内容。随着您进入数组和集合,它会变得更加清晰。 WorksheetsCollection 或大多数编程语言所称的列表。集合就像一个数组,只是您可以在中间添加新值并删除现有值。在数组中,条目只能通过索引号访问,例如:MyArray(5)。集合中的条目可以通过索引访问,但集合条目也可以有key。如果我写了Worksheets(5),这将给出错误9,因为没有工作表5。当您运行宏时,WshtDestName 的值为“数据”。没有Worksheets("Data") 所以你得到错误9。如果你更新Const 语句,这个错误就会消失,因为Worksheets("Sheet1") 存在。

我不知道开头的常量是否应该在 Sub 之后,所以我将它们移动到 Dim 之后的 Sub 之后,然后什么也没发生。

您在这里误入了“范围”的主题。如果我在子例程或函数中声明常量或变量,则它仅在该子例程或函数中可见。常量或变量的“作用域”就是函数。如果我在模块顶部声明一个常量或变量,则该模块中的每个子例程或函数都可以看到它,但其他模块中的子例程或函数不可见。常量或变量的“范围”是模块。如果我在声明中添加“Public”,则常量或变量对工作簿中每个模块或用户表单中的每个子例程或函数都是可见的。常量或变量的“范围”是工作簿。

[来自 OP 的注释:这很有趣,因为我无法通过 Google 找到关于 Sub 之前的常量的信息。谢谢。]

这个工作簿只有一个子例程和一个模块,没有用户表单,所以在哪里放置常量声明并不重要。常量或变量的最合适范围是一个复杂的问题,我不打算尝试介绍。我只想说这些常数记录了我对工作簿的假设。如果有多个模块,我会将它们定义为 Public。

您需要检查我的所有假设。我没有你的数据。我已经编造了我认为与您的数据相匹配的数据。但是,如果我对您的数据的任何假设是错误的,那么宏将不起作用。

当我按 F8 查看每一行代码时,屏幕提示如下:Application.ScreenUpdating = False 它显示为 Application.ScreenUpdating = True

当一个语句为黄色时,它还没有被执行。对于大多数语句,您实际上可以在再次按 F8 执行它之前对其进行修改。因此,如果您有一个黄色的A = A + 2 并且您认为:“我的意思是A = A + 3”,您可以在执行前更正该语句。

TrueApplication.ScreenUpdating 的默认值,因此这是您在执行 Application.ScreenUpdating = False 之前看到的值。

对于 Set WbkDest = ThisWorkbook,屏幕提示显示 WbkSet = Nothing 和 ThisWorkbook = ,但仅在黄色突出显示时才显示这些内容。当按下 F8 并移出那条线时,当我将光标放在它上面时它什么也没说。

如果您将鼠标悬停在普通变量(数据类型 = Long、String、Boolean 等)上,解释器将显示其值。一个对象(比如 WbkDest)有很多属性;解释器应该显示哪个?某些对象(例如 Range)具有默认属性。对于Range,这是Value,因此如果您将鼠标悬停在某个范围上,您会看到该值。工作簿没有默认属性,因此解释器不显示任何内容。

进入即时窗口并输入? WbkDest.Name,然后单击Enter。解释器将显示工作簿的名称。您可以获取显示的任何工作簿属性的值。您还可以显示子属性,例如:WbkDest.Worksheets.CountWbkDest.Worksheets("Sheet1").Range("A1").Value

[来自 OP 的说明:第一个错误 - 我收到运行时 '424': Object required error when I type '? WbkDest.Name' 并在即时窗口中按 Enter。是不是因为它在开头 Dim 和后来的 Set = This Workbook 中声明而无法识别 WbkDest。我将 MASTER.xlsm 的名称更改为 MASTER_DESKTOP TEST.xlsm 但这无关紧要,因为我们从未在此代码中明确提及它,对吗?]

TD 对上述注释的响应 Dim X As Type 为 X 保留一些空间并将其值设置为该类型的默认值。对于 Long 类型,该值将为零。对于 Object 类型(Workbook 是 Object 的子类型),默认值为 Nothing。没有任何东西没有任何属性,所以在这个阶段? WbkDest.Name 会给出一个错误。当语句Set WbkDest = ThisWorkbook 被执行时,WbkDest 现在可以访问ThisWorkbookThisWorkbook 有一个 Name 所以 ? WbkDest.Name 会有一个值。你是对的;您可以在不更改代码的情况下重命名工作簿。

Set RngDest = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious) 其中 RngDest = Nothing in tip 并且除了 xlFormulas 的 -4123 和1 代表 xlByRows,2 代表 xlPrevious。

据此推断,您希望将新数据添加到先前运行宏的数据底部。根据我的经验,这是不寻常的,但我包含了此选项的代码以防万一。

[来自 OP 的注释:仅供参考,是的,Master 有标题,数据将添加到之前通过宏复制的数据下方。]

TD 对上述说明的回应 我的代码比您需要的要复杂,但包含您想要的功能。如果主工作表为空,则将从第一个源工作表复制标题行和数据行。只会从任何其他工作簿复制数据行。如果主工作表不为空,则仅从源工作表复制数据行。

xlFormulas、xlByRows 和 xlPrevious 是 Excel 定义的常量,因此 Find 的参数是有意义的名称而不是奇怪的数字。

从列出的其他语句中,我推断目标工作簿当前为空。

[来自 OP 的注释:仅供参考,是的,主/目标 wkbk 在第一行有一个标题行,但一开始是空的。]

TD 对上述说明的回应查看我的最后回应。

Do While FileName "" And FileName WbkDest.Name 其中 FileName 和 WbkDest.Name = "MASTER.xlsm" 在屏幕提示中。 F8 然后跳转到代码的其余部分到最后 With WshtDest .Cells.EntireColumn.AutoFit End With 等

此时您在我的代码中遇到了一个错误。我不明白为什么我的测试没有遇到这个错误。

你需要问:为什么循环退出了?为什么下一个文件没有重复?如果我省略了大部分代码,你会得到:

Do While FileName <> "" And FileName <> WbkDest.Name
  ‘ Code to process interesting file
  FileName = Dir$
Loop  ' While FileName <> "" And FileName <> WbkDest.Name

FileName &lt;&gt; "" 是 True,因为 FileName = “MASTER.xlsm”,但 FileName &lt;&gt; WbkDest.Name 是 False,因为 “MASTER.xlsm” = WbkDest.Name。已达到结束条件,循环结束,不检查任何其他文件。

我应该写:

Do While FileName <> ""
  If FileName <> WbkDest.Name
    ‘ Code to process interesting file
  End If
  FileName = Dir$
Loop  ' While FileName <> ""

使用此代码,工作簿“MASTER.xlsm”会根据需要被忽略,但循环会继续寻找更多工作簿。

修改宏以匹配修改后的结构,然后重试。

[来自 OP 的说明:第二个错误我收到了一个编译错误 - 预期:然后或转到,所以我只是在 If FileName WbkDest.Name 之后添加了 Then,所以它显示为

If FileName <> WbkDest.Name Then
Set WbkSrc=Workbooks.Open (FolderPath & FileName)
'Rest of Code

这是正确的吗?]

TD 对上述说明的回应 是的,您是正确的。我应该包含测试代码而不是试图创建一个摘要。

[来自 OP 的注释:第三个错误 - 添加所有编辑后,我在 Run 下运行 Compile VBA Project,它说,Compile Error: Loop without Do',我不这样做'不明白,因为我确定它所指的循环位于底部,并且旁边从来没有“做”。换句话说,我不确定它为什么会在它从未有过“Do”的情况下引发错误。]

TD 对上述注释的响应 编译错误“Loop without Do”、“Do without Loop”、“If within End If”、“End If without If”等可能会造成混淆。 Do 循环、for 循环和 If 必须正确嵌套。如果你没有完全完成一个结构,编译器会抱怨可能是完美的外部结构。我的猜测是,您是否没有将End If 包含在新的If 中。当编译器命中Loop 时,它正在寻找End If 或嵌套结构的开始。我已经用我刚刚再次测试过的修改后的代码替换了我的原始代码。您可以复制新代码并更新您的姓名。但是,最好将您的循环向下工作并将其与我的匹配。我的猜测是,您会在我的代码中找到一个 End If,而您的代码中却没有。

【讨论】:

  • 非常感谢。我想学习这个 b/c 我在工作的地方我真的需要学习 VBA。请给我一些时间来研究这个,测试它,我会回复你。我不知道如果过了一段时间你是否会看到我的评论,但我会加上@符号和你的名字,希望你会看到。再次感谢你们的所有帮助。
  • @sturdy267 慢慢来;我给了你很多思考。有一些优秀的在线教程。尝试几个并完成一个与您的学习风格相匹配的课程。我更喜欢书。我参观了一个大型图书馆,查看了他们的 Excel VBA 入门书,借了我最喜欢的那些在家里尝试。最后我买了我最喜欢的一本作为永久参考书。
  • 我在上面的原始帖子末尾发布了运行代码时发生的事情。我对代码足够熟悉,尝试运行并查看会发生什么,但它不起作用。你能帮我解决问题吗?
  • 请原谅延迟响应。感谢您的回复,我回家后会查看您的帖子。工作很忙。谢谢。
  • 我将在您的“新部分以响应 OP 对原始答案的 cmets 的新部分”中添加对代码的编辑后,将我的回复作为答案的一部分,因为有一些错误消息。感谢您帮助处理此代码。我没有时间更深入地查找 Then 或 Go To 错误。
【解决方案2】:

您可以直接复制到目标范围,完全避免使用剪贴板。

Sub copyDataFromMultipleWorkbooksIntoMaster()

    Dim FileName As String, FilePath As String, FolderPath As String
    Dim lastrow As Long, lastcolumn As Long
    Dim LastCell As Range

    With ThisWorkbook.Worksheets("Sheet1")
        Set LastCell = .Cells(.Rows.Count, 1)
    End With

    FolderPath = "C:\Users\PC-1\Desktop\Merge\"
    FilePath = FolderPath & "*.xls*"
    FileName = Dir(FilePath)

    Do While FileName <> ""
        With Workbooks.Open(FolderPath & FileName)

            'Assign value to last row
            lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
            lastcolumn = .Cells(1, .Columns.Count).End(xlLeft).Column

            .Range("A2", .Cells(lastrow, lastcolumn)).Copy LastCell.End(xlUp).Offset(1)

            .Close False

        End With
        FileName = Dir

    Loop

End Sub

【讨论】:

  • #Thomas Inzina 谢谢。不过,我用这个替换了我的代码,它仍然不起作用。我输入了它,然后复制并粘贴在我的旧代码上。什么都没有发生,除了屏幕闪烁一次,就像发生了什么事情一样。我不明白为什么它不起作用。你能想到别的吗?
  • 不是按 F5 来执行代码,而是重复按 F8 来逐行执行代码。看看这是否有助于您确定正在发生的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-02
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 2017-02-09
  • 2017-02-26
  • 2021-11-05
相关资源
最近更新 更多