Sub automated_gr_lookup()
Dim st As Long
Dim en As Long
Dim c1 As Long
Dim c2 As Long
Dim iRowAsset As Integer
Dim table As Range
Dim tmpRiskID As Variant
Sheets("Geotechnical Risk Register").Select
Application.ScreenUpdating = False
Set assetTbl = Application.Range("M002_") 'Asset table = DES M002
Set riskTbl = Application.Range("geotechRisks") 'GRR
Set compiledTbl = Application.Range("CompiledM002") 'Output for M002
For iRowRisk = 1 To riskTbl.Rows.Count 'loop through risks
tmpRiskID = riskTbl.Row.Range("Ref No. ID") 'Temporary risk as it gets overridden
'if assets chainage match risk iRowRisk (4 conditions)
If (en > c1 And en < c2) Or (st > c1 And en < c2) Or (st > c1 And st < c2) Or (st < c1 And en > c2) Then
'copy asset row
assetTbl.Rows(iRowAsset).Copy
'paste row in compiled
compiledTbl.Rows(xlEndRow).PasteSpecial xlPasteValues
'paste risk id in last column of that row
compiledTbl.Cells(xlEndRow, ColumnH).Value = tmpRiskID
End If
Next iRowRisk
End Sub
我tmpRiskID = riskTbl.Row.Range("Ref No. ID")
在线遇到runtime error 424
,不知道为什么?我目前正在尝试将其分配给表标题。
Sheets("Geotechnical Risk Register").Select
这就是问题开始的地方。此工作表在哪里?如果它位于碰巧处于活动状态的任何工作簿中,则运行时错误 9"下标超出范围"等待提醒您,无论碰巧处于活动状态的工作簿,都不一定具有该名称的工作表。
如果工作表位于托管VBA代码的同一工作簿中,那么您不希望"当前处于活动状态的任何工作簿",而是ThisWorkbook
- 这已经更好了:
ThisWorkbook.Worksheets("Geotechnical Risk Register").Select
但是,您无需.Select
任何事情。考虑:
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Geotechnical Risk Register")
好多了:现在我们可以针对该特定工作表进行成员调用,并且我们知道我们正在针对正确的工作表进行工作。
除非,如果工作表在编译时存在于ThisWorkbook
中,那么它是完全多余的。
在 VBE 的项目资源管理器工具窗口中选择 Tab 模块 (Ctrl+R(,然后显示其属性(F4(。属性列表的顶部是一个(Name)
属性,目前可能类似于Sheet42
- 将其更改为更有意义的内容,例如GeotechRiskRegisterSheet
。现在,您有一个名为GeotechRiskRegisterSheet
的全局范围(实际上是项目范围(对象变量,您可以在 VBA 项目中的任何位置使用它来引用该特定工作表。
本答案的其余部分假设您已经这样做了。如果工作表不在ThisWorkbook
中,则坚持为其声明局部Worksheet
变量,并从您要使用的工作簿的Workbook.Worksheets
集合中提取Worksheet
对象引用。
Set assetTbl = Application.Range("M002_")
这是分配给一个变量,该变量似乎想要成为局部变量,但未在本地范围内的任何地方声明。Application.Range
仅比Range
略好,并且距离最明确的ActiveSheet.Range
只有一个级别的间接寻址 - 但话又说回来,你并不是要解决ActiveSheet 是什么,虽然表确实定义了命名范围,并且可以使用Range
属性访问命名范围,但这将更加清晰和绝对明确:
Dim assetTbl As ListObject
Set assetTbl = GeotechRiskRegisterSheet.ListObjects("M002_")
这同样适用于其他两个:
Set riskTbl = Application.Range("geotechRisks") 'GRR Set compiledTbl = Application.Range("CompiledM002") 'Output for M002
选择:
Dim riskTbl As ListObject
Set riskTbl = GeotechRisksSheet.ListObjects("geotechRisks")
Dim compiledTbl As ListObject
Set compiledTbl = CompiledSheet.ListObjects("CompiledM002")
然后我们开始循环:
For iRowRisk = 1 To riskTbl.Rows.Count 'loop through risks
如果riskTbl
只是另一个Range
,那么这就可以了。如果riskTbl
是一个ListObject
,我们可以做得更简单、更快:
Dim currentRow As ListRow
For Each currentRow In riskTbl.ListRows
然后我们得到你问的运行时错误:
tmpRiskID = riskTbl.Row.Range("Ref No. ID") 'Temporary risk as it gets overridden
这是错误 424"需要对象",因为riskTbl.Row
是一个Long
整数值:它没有Range
成员,所以你不能这样做Range.Row.Range
。如果您正在使用该For iRowRisk
循环迭代普通Range
,那么您希望它看起来像这样:
tmpRiskID = riskTbl.Cells(iRowRisk, 12).Value
其中12
是硬编码的列索引,指的是"Ref No.ID"列。不理想,是吗?与利用ListObject
API 相比:
Dim refIDColumn As Long
refIDColumn = riskTbl.ListColumns("Ref No. ID").Index
tmpRiskID = currentRow.Range.Cells(ColumnIndex:=refIDColumn).Value
如果在循环外部定义refIDColumn
变量,则每次迭代都可以重用其值,并且只要标题标题保持"Ref No.ID",该列可以是用户想要的任何位置 - 而对于硬编码的列索引,如果用户插入新列,代码就会中断。
'if assets chainage match risk iRowRisk (4 conditions) If (en > c1 And en < c2) Or (st > c1 And en < c2) Or (st > c1 And st < c2) Or (st < c1 And en > c2) Then
我希望您在实际代码中声明并分配了这些变量 - 否则无法可靠地计算此条件表达式,因为这些标识符都没有值。考虑使用有意义的名称来传达使用意图:en
、st
、c1
,c2
对于任何不太熟悉编写该代码的人的思维过程的人来说,绝对没有任何意义。无论如何,请确保模块的顶部显示Option Explicit
某处。
'copy asset row assetTbl.Rows(iRowAsset).Copy 'paste row in compiled compiledTbl.Rows(xlEndRow).PasteSpecial xlPasteValues 'paste risk id in last column of that row compiledTbl.Cells(xlEndRow, ColumnH).Value = tmpRiskID
我不相信你真的需要在这里涉及剪贴板。同样,考虑利用ListObject
API - 这应该有效(未经测试(:
With compiledTbl.ListRows.Add
.Range.Value = currentRow.Range.Value
.Range.Cells(ColumnIndex:=compiledRiskIdColumn).Value = tmpRiskID
End With
在循环体之前声明和分配compiledRiskIdColumn
:
Dim compiledRiskIdColumn As Long
compiledRiskIdColumn = compieldTbl.ListColumns("Risk ID").Index '<~ verify column title