我为一位同事创建了一个函数,其工作方式类似于 xLookUp,但允许用户返回 N
从找到的最后一场比赛开始。为了使该功能正常工作,我必须为用户添加一个参数以输入 Worksheet.Name。如果没有这个参数,如果 lookup_sheet 不是输入函数的工作表,我无法让函数从正确的工作表返回值。我了解 Application.Caller 方法可用于确保代码正在查看输入函数的工作表,但我如何让它查看范围参数设置的工作表?
我在名为“Supplies_List”的工作表中输入的函数读取为 =xLookUp_X_From_Last (D2,"Orders",Orders!E:E,Orders!I:I,"",2)
代码是:
Public Function xLookUp_X_From_Last(ByVal LookUp_Value As String, ByVal LookUp_Sheet As String, ByVal LookUp_Column As Range, ByVal Return_Column As Range, ifNA As String, Return_From_Last As Long) As String
Dim myCol As Collection
Dim i, LR, colCount, lColumn, rColumn, lookBack As Long
Dim lLetter, cLetter, s As String
Dim lSheet As Worksheet
Dim wb As Workbook
Set wb = ActiveWorkbook
Set lSheet = wb.Worksheets(LookUp_Sheet)
lookBack = Return_From_Last - 1
If LookUp_Column.Columns.Count <> 1 Or Return_Column.Columns.Count <> 1 Then
xLookUp_X_From_Last = "SELECTED RANGE ERROR"
Exit Function
End If
If LookUp_Value = "" Then
xLookUp_X_From_Last = ifNA
Exit Function
End If
Set myCol = New Collection
lColumn = LookUp_Column.Column
rColumn = Return_Column.Column
lLetter = Split(Cells(1, lColumn).Address, "$")(1)
LR = lSheet.Range(lLetter & Rows.Count).End(xlUp).Row
For i = 1 To LR
If lSheet.Cells(i, lColumn).Value = LookUp_Value Then
myCol.Add lSheet.Cells(i, rColumn).Value
End If
Next i
colCount = myCol.Count
If (colCount - lookBack) < 1 Then
s = ifNA
Else
s = myCol(colCount - (lookBack))
End If
xLookUp_X_From_Last = s
End Function
即使 LookUp_Column
参数使用 Orders!E:E
引用工作表,我必须添加 LookUp_Sheet
争论。我很擅长子程序,但不太擅长函数,这让我很困惑。我从高处和低处寻找vLookUp和xLookUp的VBA代码来剖析和学习,但找不到。如果有人可以将我指向这些功能的源代码,那也很棒。
最佳答案
(一) 如评论中所述,您可以通过 Parent
获取范围的工作表-属性(property)
(二) 在 VBA 中几乎不需要处理列字符。
(c) 小心你的变量声明。如果要在一行中声明多个变量,则需要为每个变量指定类型,否则仅指定类型的最后一个变量,所有其他变量都声明为Variant
.参见示例 https://stackoverflow.com/a/71250993/7599798
(d) 子例程和函数之间几乎没有区别,只是函数返回一个值。如果你想将该函数用作UDF,你有一些(明显的)限制,例如不要修改底层的excel,不要使用Select
和 Activate
- 但无论如何你都不应该在 VBA 中使用它。
看看下面的函数。出于速度原因,我将查找和返回范围读入一个数组,特别是对于 UDF 速度很重要,这减少了 Excel 和 VBA 之间的往返次数。我还将最后两个参数设为可选。
Public Function xLookUp_X_From_Last(ByVal LookUp_Value As String, _
ByVal LookUp_Column As Range, ByVal Return_Column As Range, _
Optional ifNA As String = "not found", _
Optional Return_From_Last As Long = 1) As String
Dim myCol As Collection
Dim i As Long, LR As Long, lookBack As Long
lookBack = Return_From_Last - 1
If LookUp_Column.Columns.Count <> 1 Or Return_Column.Columns.Count <> 1 Then
xLookUp_X_From_Last = "SELECTED RANGE ERROR"
Exit Function
End If
If LookUp_Value = "" Then
xLookUp_X_From_Last = ifNA
Exit Function
End If
Set myCol = New Collection
Dim lookupValues As Variant, returnValues As Variant
With LookUp_Column.Parent
LR = .Cells(.Rows.Count, LookUp_Column.Column).End(xlUp).Row
lookupValues = LookUp_Column.Cells(1, 1).Resize(LR, 1)
returnValues = Return_Column.Cells(1, 1).Resize(LR, 1)
End With
For i = LBound(lookupValues) To UBound(lookupValues)
If lookupValues(i, 1) = LookUp_Value Then
myCol.Add CStr(returnValues(i, 1)), CStr(i)
End If
Next i
If (myCol.Count - lookBack) < 1 Then
xLookUp_X_From_Last = ifNA
Else
xLookUp_X_From_Last = myCol(myCol.Count - lookBack)
End If
End Function
更新 : 你不需要 Application.Caller。如果您将公式放入工作表中,例如=xLookUp_X_From_Last (D2,Orders!E:E,Orders!I:I,"",2)
Excel 会将前 3 个参数转换为 Range
-variables,并且 Range 总是自动属于一个(并且只有一个)工作表。第一个参数 (
D2
) 将指向公式所在的同一工作表的单元格 D2,接下来的两个参数将指向工作表 Orders
的 E 列和 I 列.不要被
Range.Address
的事实所迷惑。不显示工作表名称 - Range 不是地址,它是指向工作表上一个或多个单元格的对象。
关于excel - 如何在用户定义的 VBA 函数中从另一个工作表中提取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71299165/