Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Loops VBA溢出似乎没有任何原因_Loops_Excel_Overflow_Vba - Fatal编程技术网

Loops VBA溢出似乎没有任何原因

Loops VBA溢出似乎没有任何原因,loops,excel,overflow,vba,Loops,Excel,Overflow,Vba,我试图将唯一值从一个documents k列写入另一个工作簿的ad列。 当我将I设置为字符串时,它会给出溢出错误;当我将I设置为字符串时,它会给出错误1004:应用程序定义的错误或对象定义的错误。对于含有CarID Cellsi+1,11的线,两者都适用。 即使我不使用循环直到,但我使用退出做。 这一部分是必需的,因为read列包含大约10个实例的相同数据。不完全是,每个值都会发生变化。 对于前3个值,该代码正常工作,然后被卡住并出现错误。我尝试将值更改为a。Bc同样的问题也存在。 感谢您的帮助

我试图将唯一值从一个documents k列写入另一个工作簿的ad列。 当我将I设置为字符串时,它会给出溢出错误;当我将I设置为字符串时,它会给出错误1004:应用程序定义的错误或对象定义的错误。对于含有CarID Cellsi+1,11的线,两者都适用。 即使我不使用循环直到,但我使用退出做。 这一部分是必需的,因为read列包含大约10个实例的相同数据。不完全是,每个值都会发生变化。 对于前3个值,该代码正常工作,然后被卡住并出现错误。我尝试将值更改为a。Bc同样的问题也存在。 感谢您的帮助,以下是代码:

Sub PrintCarID()

Dim ABC_App As Excel.Application
Dim carPath As String
Dim carWBook As Excel.Workbook
Dim MigrationDocument As Excel.Workbook

Dim CarID As String
Dim i As Long
Dim n As Integer
i = 0
n = 1

Set MigrationDocument = ActiveWorkbook       'activeworkbook is the document we need to print in
carPath = Cells(ActiveCell.Row, 29).Value    'the path and filename for the read document
Set carWBook = Workbooks.Open(carPath)
Set ABC_App = carWBook.Parent
ABC_App.Visible = True


Do
carWBook.Activate
Do
i = i + 1
CarID = Cells(i, 11).Value


Loop Until CarID <> Cells(i + 1, 11)

MigrationDocument.Activate
Cells(n, 30).Value = CarID
n = n + 1

Loop Until CarID = ""

End Sub

你说你只得到前三个唯一的值。我不能重复那个问题。试试我的代码,看看它是否解决了这个问题。如果不是,我只能假设我误解了您数据的性质。我发布测试数据的图像。你需要告诉我我的数据与你的数据有什么不同

Rory的评论表明,有更先进的技术可能是合适的。虽然我对您的代码做了很多更改,但我避免了这些高级技术。我已经给了你足够的思考。掌握我所有的观点和我所有改变的原因,你将为下一个级别做好准备

一般要点

工作簿。打开在当前Excel副本中打开一个新工作簿。您不需要:

Dim ABC_App As Excel.Application

Set ABC_App = carWBook.Parent
ABC_App.Visible = True
有时,从ActiveCell或相对于ActiveCell拾取值是必要且适当的。你确定这是其中之一吗?用户是否记得将源工作簿的名称放在离开光标所在行的第29列?他们会忘记并留下上一个工作簿的名称吗?请扪心自问,这是否是获取源工作簿名称的最可靠方法

您假定源工作簿将在源工作表打开的情况下保存。你确定这是真的吗

我已经用过了。这将是99%的正确方法。只有你知道在这种情况下这是不是正确的方法

避免激活工作表。这是一个缓慢的命令,特别是当您忽略Application.ScreenUpdate=False时,因为每次激活新工作表时,Excel都会重新绘制屏幕

从活动单元格行的第29列中获取一个值,并立即在Worksbooks.Open语句中使用该值。您不需要检查该值是否不为null,以及它是否是可访问工作簿的路径和名称。养成检查尽可能多的错误的习惯,这样你就可以给用户一个可以理解的错误消息和一个优雅的退出,而不是一个突出显示的VBA语句和一个来自VBA解释器的模糊错误消息

避免使用像i和n这样的名字。在编写此宏时,您将记住i和n是什么。您还记得在六个月或十二个月内何时需要更新此宏吗?我使用像RowSrcCrnt和RowDestCrnt这样的名称。我不是要你喜欢我的命名系统,而是要你有自己的命名系统。我可以回到几年前写的宏,知道所有的变量是什么。当您需要更新旧宏时,这是一个实时节省器

避免我称之为幻数的数字,如11、29和30。今天,要检查的数据位于第11列,但您确定不会添加新的第2列吗。在重新排列工作表后通过宏更新它可能是一场噩梦。使用常量意味着键入语句需要更长的时间,但如果您使用有意义的名称,则代码是自文档化的,这样可以在发生更改时节省大量时间。通常,只需更新常量值即可

我的测试数据和代码

运行宏之前,包含宏的工作簿中工作表的我的版本如下所示:

包含数据的工作簿中工作表的我的版本如下所示:

运行宏后,包含宏的工作簿中工作表的我的版本如下所示:

以上图像符合我对代码的理解

我的代码如下。我已经解释了我所做的每一个改变。其中一些更改可能不适合您当前的要求。我的更改在大多数情况下都是正确的,但现在只有您才能知道它们是否正确。通过我的代码工作。如果有必要,带着问题回来,但是你自己越能理解这些变化,你的发展就越快。祝你好运

Option Explicit
Sub PrintCarID()

  ' * I name my constant and variables using a sequence of keywords.
  ' * The first keyword identifies the type of information.  For example:
  '   Wsht for worksheet, Wbk for workbook, Row for row, Col for column and
  '   Rng for range.
  ' * Each subsequent keyword narrows the constant or variable down until
  '   I hsve a name that is unique within the macro or project.
  ' * If I have more than one workbook, the keyword following Wbk will identify
  '   the workbook. I know nothing about your workbooks and worksheets so have
  '   named them Source and Destination and have used keywords Src and Dest.
  ' * This is my system which you may not like.  If you do not like mine,
  '   invent your own.  Naming your constants and variables makes large macro
  '   much easier to follow particularly if you return to one after 6 or 12
  '   months.

  ' * 11 and 30 in your code are what I call magic numbers.  You say "Abracadabra!"
  '   and good (or bad) things happen but you do not know why.  Replacing 11 and 30
  '   with names makes the code easier to understand and easier to maintain.
  Const ColSrcId As Long = 11
  Const ColDestId As Long = 30

  ' * I do not like using the cell that was active when the macro was called
  '   unless this is important to how the user controls the macro. Switch
  '   back to your approach if necessary.
  Const RngWbkSrcName As String = "AC1"

  ' Chamge these values if you add header rows
  Const RowSrcDataFirst As Long = 1
  Const RowDestDataFirst As Long = 1

  ' * You use the active worksheet in the workbook containing the macro and the
  '   worksheet active when the source worksheet was saved.  This may be
  '   necessary for your macro but I have coded on the assumption it is not.
  '   Switch back to ActiveWorkbook if necessary.  Better replace "Destination"
  '   and "Source" with your names.
  Const WshtDestName As String = "Destination"
  Const WshtSrcName As String = "Source"

  Dim CarIdLast As String
  Dim Path As String
  Dim RowDestCrnt As Long
  Dim RowSrcCrnt As Long
  Dim RowSrcLast As Long
  Dim WbkDest As Workbook
  Dim WbkSrc As Workbook
  Dim WbkSrcName As String
  Dim WshtDest As Worksheet
  Dim WshtSrc As Worksheet

  ' * ThisWorkbook explicitly identifies the workbook containing the macro
  '   It is possible to execute a macro in a non-active workbook so ActiveWorkbook
  '   is not necessarily the workbook containing the macro
  Set WbkDest = ThisWorkbook        ' The workbook containing the macro

  With WbkDest

    Set WshtDest = Worksheets(WshtDestName)

    With WshtDest

      ' * carPath may be a meaningful name for you but I have used my own naming
      '   convention.  If "car" is meaningful, I would use a name like WbkCarName
      '   or WbkCarPath.
      WbkSrcName = .Range(RngWbkSrcName).Value

    End With
  End With

  If WbkSrcName = "" Then
    Call MsgBox("The name of the source workbook is missing.", vbOKOnly)
    Exit Sub
  End If

  ' * I like to place all linked workbooks and files in the same folder
  '   since this makes it easier to handle them. With your approach the
  '   user has to include the full path within the workbook name. With
  '   my approach the user only has to include specify the file name.
  Path = WbkDest.Path & "\"

  ' * Check the path and file exists.  I could check the path exists first
  '   but I doubt that would provide much extra help to the user
  If Dir$(Path & WbkSrcName) = "" Then
    Call MsgBox("I cannot find """ & Path & WbkSrcName & """.", vbOKOnly)
    Exit Sub
  End If

  ' * I have checked the file exists but the open may still fail because,
  '   for example, I may not have read permission.  There is little I can
  '   do to avoid such errors.  Te statements around the Workbook.Open
  '   switch off normal error processing so I can issue my own error
  '   message rather than have the VBA halt on the Workbook.Open statement.
  Err.Clear
  On Error Resume Next
  Set WbkSrc = Workbooks.Open(Path & WbkSrcName)
  On Error GoTo 0
  If Err.Number <> 0 Then
    Call MsgBox("My attempt to open """ & Path & WbkSrcName & """failed. " & _
                "The reason I have been given is: " & Err.Description, vbOKOnly)
    Exit Sub
  End If

  ' * You step the source row number then check it but output to the destination
  '   row then step. I  like to be consistent unless there is good reason not to
  '   be consistent.  I step afterwards for both rows.
  ' * You do not allow for header rows.  This may be correct at the moment but
  '   will it always be correct.  I allow for header rows to be added easily
  '   by making the first data row a constant
  RowDestCrnt = RowDestDataFirst

  CarIdLast = ""        ' No last Car Id

  With WbkSrc

    ' * If I was particularly careful, I would check a worksheet with name
    '   WshtSrcName exists before trying this statement.
    Set WshtSrc = Worksheets(WshtSrcName)

    With WshtSrc

      ' * This gets the last used row in column ColSrcId.  This allows me to
      '   use a For-Loop which I find clearer.
      RowSrcLast = .Cells(Rows.Count, ColSrcId).End(xlUp).Row

      For RowSrcCrnt = RowSrcDataFirst To RowSrcLast
        If CarIdLast <> .Cells(RowSrcCrnt, ColSrcId).Value Then
          ' * New value for CarId
          If CarIdLast <> "" Then
            ' * Have a value to copy to the destination worksheet
            WshtDest.Cells(RowDestCrnt, ColDestId).Value = CarIdLast
            RowDestCrnt = RowDestCrnt + 1
          End If
          CarIdLast = .Cells(RowSrcCrnt, ColSrcId).Value
        End If
      Next
      ' * Output final value
      If CarIdLast <> "" Then
        ' * Have a value to copy to the destination worksheet
        WshtDest.Cells(RowDestCrnt, ColDestId).Value = CarIdLast
        RowDestCrnt = RowDestCrnt + 1
      End If

    End With

    ' * Close the source workbook without saving any changes.  There should not
    '   be any changes but best to be safe.  Without SaveChanges the user will
    '   be asked if changes are to be saved.
    .Close SaveChanges:=False

  End With

End Sub

移动第11列中的最终值后,可以从第一个空行设置CarID。然后循环,直到找到一个非空行。我猜字符串I被视为整数,并在32768处溢出。对于long i,当您试图访问不存在的行时会出现错误。最大行数取决于您的Excel版本。试试你的代码,当它失败时告诉我i的值。如果我的理论是正确的,我会
我用你的代码的正确版本发布一个答案。如果源数据有标题行,你可以使用字典,或者只是一个高级过滤器。你是对的,托尼,如果失败时是字符串,那么i的值是32767。我修改了代码,在嵌套循环中添加了exit do if carID=。然而,代码仍然只打印前三个唯一的值,即使文档中有大约8个,我正在与Tony一起测试代码,我不希望得到更详细、更广泛和更现成的答案。我正在阅读你的代码,我仍然看到一些我不熟悉的关键字,但我现在正在赶上这些,代码变得越来越清晰。我很喜欢你的命名惯例和提示。对于像我这样的新手来说,这是一个完美的答案和完美的态度。非常感谢。我很高兴我的回答很有帮助。请点击顶部的提纲勾号接受答案。