【发布时间】:2023-02-22 00:56:39
【问题描述】:
第一次海报,长期潜伏者。
我正在尝试为到目前为止我使用公式完成的事情创建一些 VBA 代码。具体来说,我想根据两个条件从 SourceSheet 中查找值,并将第 7 列中的值返回到 TargetSheet。这是为了提取一些财务数据,例如工作子类型的总体利润率百分比。
我遇到的问题不是所有 TargetSheets 行(Criteria1 和 Criteria3)都会在 SourceSheet 中找到,有些会找到但值将为空。这导致代码在以下部分抛出类型不匹配错误:
“如果 IsError(Application.Index(Source Range, Application.Match(Criteria1 and Criteria2, Source Range.Columns(4) & SourceRange.Columns(5), 0), 6)) 然后”
我尝试了很多不同的方法来解决这个问题,但都导致类型不匹配。任何帮助表示赞赏!
Sub Margin_Trade_Update()
Dim SourceWB As Workbook, TargetWB As Workbook
Dim SourceSheet As Worksheet, TargetSheet As Worksheet
Dim Criteria1 As String, Criteria2 As String
Dim SourceRange As Range, TargetRange As Range
Dim MatchLC As Long, MatchTrade As Long
Dim LastRow As Long
Dim ResultCol As Long
'Set the source and target workbooks
Set SourceWB = Workbooks.Open("Path and Source workbook name")
Set TargetWB = ThisWorkbook
'Set the source and target worksheets
Set SourceSheet = SourceWB.Sheets("Margin - Trade")
Set TargetSheet = TargetWB.Sheets("01-25")
'Delete the first two rows of margin trade sheet
SourceSheet.Range("A1:A2").EntireRow.Delete
'Determine the last row in the target sheet
LastRow = TargetSheet.Cells(TargetSheet.Rows.Count, "A").End(xlUp).Row
'Iterate through the rows in the target sheet for MTD Trade Margin
For i = 2 To LastRow
'Set the criteria and target range
Criteria1 = TargetSheet.Cells(i, "H").Value
Criteria2 = TargetSheet.Cells(i, "M").Value
Set TargetRange = TargetSheet.Cells(i, "AB")
'Find the match row and column in the source range
With SourceSheet
Set SourceRange = .Range(.Cells(1, 1), .Cells(.Rows.Count, .Columns.Count))
MatchLC = IIf(IsError(Application.Match(Criteria1, .Columns(4), 0)), 0, Application.Match(Criteria1, .Columns(4), 0))
MatchTrade = IIf(IsError(Application.Match(Criteria2, .Columns(5), 0)), 0, Application.Match(Criteria2, .Columns(5), 0))
End With
'Use INDEX and MATCH to retrieve the value from the source range
If IsError(Application.Index(SourceRange, Application.Match(Criteria1 & Criteria2, SourceRange.Columns(4) & SourceRange.Columns(5), 0), 6)) Then
TargetRange.Value = ""
Else
TargetRange.Value = Application.Index(SourceRange, Application.Match(Criteria1 & Criteria2, SourceRange.Columns(4) & SourceRange.Columns(5), 0), 6)
On Error GoTo 0
End If
Next i
'Close the source workbook
SourceWB.Close SaveChanges:=False
End Sub
谢谢@DecimalTurn!
这是我使用自定义函数更新后的代码,但我试着让它运行 20 分钟,但只是旋转......
Function MatchWith2Criteria(LookUpRange1 As Range, Criteria1 As Variant, LookUpRange2 As Range, Criteria2 As Variant) As Variant
'N/A by default
MatchWith2Criteria = CVErr(xlErrNA)
'We need the two ranges to have the same height or we won't be able to align them
If (LookUpRange1.Rows.Count <> LookUpRange2.Rows.Count) Then
Exit Function
End If
'Here we are storing the values from the ranges inside arrays. This is mainly to improve performance as VBA doesn't have to access the worksheet data constantly.
Dim arr1() As Variant
arr1 = LookUpRange1.Columns(1).Value2
Dim arr2() As Variant
arr2 = LookUpRange2.Columns(1).Value2
Dim i As Long
For i = 1 To UBound(arr1)
If arr1(i, 1) = Criteria1 And arr2(i, 1) = Criteria2 Then
MatchWith2Criteria = i
Exit Function
End If
Next
End Function
Sub Margin_Trade_Update_V2()
' Update JCA tab with MTD Trade Margin
Dim SourceWB As Workbook, TargetWB As Workbook
Dim SourceSheet As Worksheet, TargetSheet As Worksheet
Dim Criteria1 As String, Criteria2 As String
Dim SourceRange As Range, TargetRange As Range
Dim MatchLC As Long, MatchTrade As Long
Dim LastRow As Long
Dim ResultCol As Long
'Set the source and target workbooks
Set SourceWB = Workbooks.Open("Path & File")
Set TargetWB = ThisWorkbook
'Set the source and target worksheets
Set SourceSheet = SourceWB.Sheets("Margin - Trade")
Set TargetSheet = TargetWB.Sheets("01-25")
'Delete the first two rows of margin trade sheet
SourceSheet.Range("A1:A2").EntireRow.Delete
'Determine the last row in the target sheet
LastRow = TargetSheet.Cells(TargetSheet.Rows.Count, "A").End(xlUp).Row
'Iterate through the rows in the target sheet for MTD Trade Margin
For i = 2 To LastRow
'Set the criteria and target range
Criteria1 = TargetSheet.Cells(i, "H").Value
Criteria2 = TargetSheet.Cells(i, "M").Value
Set TargetRange = TargetSheet.Cells(i, "AB")
'Find the match row and column in the source range
With SourceSheet
Set SourceRange = .Range(.Cells(1, 1), .Cells(.Rows.Count, .Columns.Count))
'MatchLC = IIf(IsError(Application.Match(Criteria1, .Columns(4), 0)), 0, Application.Match(Criteria1, .Columns(4), 0))
'MatchTrade = IIf(IsError(Application.Match(Criteria2, .Columns(5), 0)), 0, Application.Match(Criteria2, .Columns(5), 0))
End With
'Use INDEX and MATCH to retrieve the value from the source range
Dim MyMatch As Variant
MyMatch = MatchWith2Criteria(SourceSheet.Columns(3), Criteria1, SourceSheet.Columns(4), Criteria2)
If IsError(MyMatch) Then
TargetRange.Value2 = ""
Else
TargetRange.Value2 = Application.Index(SourceRange, MyMatch, 6)
End If
Next i
End Sub
最后感谢@DecimalTurn 帮助我度过难关!
这是我所做更改的最终代码和一些 cmets:
'Needed to define the function so instead of figuring out how to nest it i just went the 'ol fashioned way
Function MatchOrZero(ByVal LookupVal As Variant, ByVal LookupRange As Range, Optional ByVal ReturnType As Long = 1) As Variant
On Error Resume Next
MatchOrZero = Application.Match(LookupVal, LookupRange, ReturnType)
If IsError(MatchOrZero) Then
MatchOrZero = 0
End If
On Error GoTo 0
End Function
Sub Margin_Trade_Update_V3()
' Update JCA tab with MTD Trade Margin
Dim SourceWB As Workbook, TargetWB As Workbook
Dim SourceSheet As Worksheet, TargetSheet As Worksheet
Dim SourceRange As Range, TargetRangeMTD As Range, TargetRangeLTD As Range
Dim LastRow As Long
Dim ResultCol As Long
'Set the source and target workbooks
Set SourceWB = Workbooks.Open("Path & File Here")
Set TargetWB = ThisWorkbook
'Set the source and target worksheets
Set SourceSheet = SourceWB.Sheets("Margin - Trade")
Set TargetSheet = TargetWB.Sheets("01-25")
'Delete the first two rows of margin trade sheet
SourceSheet.Range("A1:A2").EntireRow.Delete
'Determine the last row in the target sheet
LastRow = TargetSheet.Cells(TargetSheet.Rows.Count, "A").End(xlUp).Row
'Iterate through the rows in the target sheet for MTD Trade Margin
Dim i As Long
For i = 2 To LastRow
'Set the criteria and target range
Dim Criteria1 As String, Criteria2 As String
Criteria1 = TargetSheet.Cells(i, "H").Value
Criteria2 = TargetSheet.Cells(i, "M").Value
Set TargetRangeMTD = TargetSheet.Cells(i, "AB")
Set TargetRangeLTD = TargetSheet.Cells(i, "AC")
'Find the match row and column in the source range
With SourceSheet
Set SourceRange = .Range(.Cells(1, 1), .Cells(.Rows.Count, .Columns.Count))
Dim MatchLC As Long
MatchLC = MatchOrZero(Criteria1, .Columns(4), 0)
Dim MatchTrade As Long
MatchTrade = MatchOrZero(Criteria2, .Columns(5), 0)
End With
'Use INDEX and MATCH to retrieve the value from the source range
Dim MyMatch As Variant
'N/A by default
MyMatch = CVErr(xlErrNA)
Dim LookUpRange1 As Range
Dim LookUpRange2 As Range
'needed to define SourceSheetLastRow
Dim SourceSheetLastRow As Long
SourceSheetLastRow = SourceSheet.Cells(SourceSheet.Rows.Count, "A").End(xlUp).Row
If LookUpRange1 Is Nothing Then
Set LookUpRange1 = SourceSheet.Range(SourceSheet.Cells(1, 4), SourceSheet.Cells(SourceSheetLastRow, 4))
Set LookUpRange2 = SourceSheet.Range(SourceSheet.Cells(1, 5), SourceSheet.Cells(SourceSheetLastRow, 5))
'Here we are storing the values from the ranges inside arrays. This is mainly to improve performance as VBA doesn't have to access the worksheet data constantly.
Dim arr1() As Variant
'Note here that you don't need to specify Columns(1) if LookUpRange is always a single-column range.
arr1 = LookUpRange1.Columns(1).Value2
Dim arr2() As Variant
arr2 = LookUpRange2.Columns(1).Value2
End If
Dim j As Long
For j = 1 To UBound(arr1)
If arr1(j, 1) = Criteria1 Then
If arr2(j, 1) = Criteria2 Then
'MyMatch = i - Needed to be j in this loop
MyMatch = j
Exit For
End If
End If
Next j
If IsError(MyMatch) Then
TargetRangeMTD.Value = ""
TargetRangeLTD.Value = ""
Else
TargetRangeMTD.Value2 = Application.Index(SourceRange, MyMatch, 6)
TargetRangeLTD.Value2 = Application.Index(SourceRange, MyMatch, 7)
End If
Next i
End Sub
【问题讨论】: