我正在尝试将一个文档k列中的唯一值写入不同的工作簿的广告列。 当我将其作为字符串调暗时,它会产生溢出错误,当我将其调暗为长时,它会给出错误1004:应用程序定义或对象定义错误。两者都包含CarID<>细胞(i + 1,11)。 即使我不使用循环,但我使用退出做。 该部分是必需的,因为读取列包含大约10个实例的相同数据。不完全是,每个值的变化。 代码适用于前3个值然后卡住并给出错误。我尝试将值更改为a。湾c同样的问题包括。 感谢您的帮助,以下是代码:
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
答案 0 :(得分:0)
你说你只获得前三个唯一值。我无法复制这个问题。尝试我的代码,看看它是否解决了这个问题。如果不是,我只能假设我误解了数据的性质。我发布了测试数据的图像。您需要告诉我我的数据与您的数据有何不同。
Rory的评论表明,有更多先进的技术可能是合适的。虽然我对您的代码做了很多更改,但我已经避免使用这些高级技术了。我给了你很多想法。掌握我的所有观点以及所有变更的原因,您将为下一级做好准备。
一般要点
Workbooks.Open
在当前的Excel副本中打开一个新工作簿。你不需要:
Dim ABC_App As Excel.Application
Set ABC_App = carWBook.Parent
ABC_App.Visible = True
有时需要从ActiveCell
或相对于With
获取值。你确定这是其中之一吗?用户是否记得将源工作簿的名称放在离开光标的行的第29列?他们会忘记并保留以前工作簿的名称吗?请问自己这是否是获取源工作簿名称的最可靠方法。
您假设源工作簿已保存,源工作表已打开。你确定这是真的吗?
我使用了Application.ScreenUpdating = False
个名字。这将是99%的正确方法。只有你能在这种情况下知道它是否是正确的方法。
避免激活工作表。这是一个缓慢的命令,特别是如果省略Worksbooks.Open
,因为每次激活新工作表时Excel都会重新绘制屏幕。
您从活动单元格行的第29列获取值,并立即在i
语句中使用它。您不检查值是否为null,并且它是可访问工作簿的路径和名称。养成检查尽可能多的错误的习惯,这样您就可以为用户提供可理解的错误消息和优雅的退出,而不是突出显示的VBA语句和来自VBA解释器的模糊错误消息。
避免使用n
和i
等名称。在编写此宏时,您会记住n
和RowSrcCrnt
的内容。你还记得你需要在六到十二个月内更新这个宏吗?我使用RowDestCrnt
和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,29和30.今天,要检查的数据位于第11列,但您确定不会添加新的第2列。在工作表重新排列后通过宏更新它可能是一场噩梦。使用常量意味着键入语句需要更长的时间,但如果使用有意义的名称,则代码是自我记录的,并且当某些内容发生更改时可以节省大量时间。经常更新常量值是必要的。
我的测试数据和代码
在运行宏之前,包含宏的工作簿中的工作表版本如下所示:
包含数据的工作簿中的工作表版本如下所示:
运行宏后,包含宏的工作簿中的工作表版本如下所示:
以上图片符合我对您的代码的理解。
我的代码如下。我已经解释了我所做的每一项改变。其中一些更改可能不适合您当前的要求。我的更改大部分时间都是正确的,但只有你现在才知道它们是否正确。通过我的代码工作。如有必要,请回答问题,但是你越了解自己的变化,你就会越快发展。祝你好运。
{{1}}