VBA for Access 缺少一个简单的Max(x,y)
函数来查找两个或多个值的数学最大值。我习惯于在来自其他语言(如 perl/php/ruby/python 等)的基本 API 中已经有了这样的功能。
我知道可以做到:IIf(x > y, x,y)
。还有其他可用的解决方案吗?
VBA for Access 缺少一个简单的Max(x,y)
函数来查找两个或多个值的数学最大值。我习惯于在来自其他语言(如 perl/php/ruby/python 等)的基本 API 中已经有了这样的功能。
我知道可以做到:IIf(x > y, x,y)
。还有其他可用的解决方案吗?
我将把问题解释为:
如何在 Access 中实现一个返回数字数组的 Max/Min 的函数?这是我使用的代码(与 IIf 类比命名为“iMax”,即“Immediate If”/“Immediate Max”):
Public Function iMax(ParamArray p()) As Variant
' Idea from Trevor Best in Usenet MessageID rib5dv45ko62adf2v0d1cot4kiu5t8mbdp@4ax.com
Dim i As Long
Dim v As Variant
v = p(LBound(p))
For i = LBound(p) + 1 To UBound(p)
If v < p(i) Then
v = p(i)
End If
Next
iMax = v
End Function
Public Function iMin(ParamArray p()) As Variant
' Idea from Trevor Best in Usenet MessageID rib5dv45ko62adf2v0d1cot4kiu5t8mbdp@4ax.com
Dim i As Long
Dim v As Variant
v = p(LBound(p))
For i = LBound(p) + 1 To UBound(p)
If v > p(i) Then
v = p(i)
End If
Next
iMin = v
End Function
至于为什么 Access 不会实现它,在我看来,这并不是一件很常见的事情。它也不是很“数据库”。您已经获得了跨域和成组查找 Max/Min 所需的所有功能。它也不是很难实现,或者只是在需要时将其编码为一次性比较。
也许以上内容会对某人有所帮助。
如果您添加对 Excel 的引用 ( Tools
→ References
→ Microsoft Excel x.xx Object Library
),那么您可以WorksheetFunction
用来调用大多数 Excel 工作表函数,包括MAX
(也可以在数组上使用)。
例子:
MsgBox WorksheetFunction.Max(42, 1999, 888)
或者,
Dim arr(1 To 3) As Long
arr(1) = 42
arr(2) = 1999
arr(3) = 888
MsgBox WorksheetFunction.Max(arr)
第一个电话需要一秒钟的时间来响应(实际上对我来说是 1.1 秒),但随后的电话更合理(对我来说每个电话<0.002 秒)。
如果您在过程中使用了大量 Excel 函数,则可以通过使用Application
对象直接引用 Excel 来进一步提高性能。
例如,此过程迭代一组记录,MAX
在字节数组上重复使用 Excel 来确定每条记录的“最高”ASCII 字符。
Option Compare Text
Option Explicit
'requires reference to "Microsoft Excel x.xx Object Library"
Public excel As New excel.Application
Sub demo_ListMaxChars()
'list the character with the highest ASCII code for each of the first 100 records
Dim rs As Recordset, mx
Set rs = CurrentDb.OpenRecordset("select myField from tblMyTable")
With rs
.MoveFirst
Do
mx = maxChar(!myField)
Debug.Print !myField, mx & "(" & ChrW(mx) & ")" '(Hit CTRL+G to view)
.MoveNext
Loop Until .EOF
.Close
End With
Set rs = Nothing 'always clean up your objects when finished with them!
Set excel = Nothing
End Sub
Function maxChar(st As String)
Dim b() As Byte 'declare Byte Array
ReDim b(1 To Len(st)) 'resize Byte Array
b = StrConv(st, vbFromUnicode) 'convert String to Bytes
maxChar = excel.WorksheetFunction.Max(b) 'find maximum Byte (with Excel function)
End Function
因为他们可能认为您会使用 DMAX 和 DMIN 或 sql MAX 并且只使用访问中的数据库?
我也很好奇为什么.. 必须创建一个临时表并将表单值添加到表中然后在表上运行 DMAX 或 MAX 查询以获得结果似乎有点过头了......
众所周知,我创建了一个小的 projMax() 函数来处理这些问题。并不是说 VBA 可能会得到增强,但以防万一他们确实添加了适当的 Max(和 Min)函数,它不会与我的函数冲突。顺便说一句,原始海报建议做 IIF ......这行得通,但在我的函数中,我通常会抛出几个 Nz() 以防止 null 破坏函数。
我喜欢 DGM 使用 IIF 语句和 David 使用 For/Next 循环,所以我将它们组合在一起。
因为 VBA 在访问中没有严格的类型检查,所以我将使用变体来保留所有数字、整数和小数,并重新键入返回值。
感谢 HansUP 捕获我的参数验证 :)
添加评论以使代码更友好。
Option Compare Database
Option Base 0
Option Explicit
Function f_var_Min(ParamArray NumericItems()) As Variant
If UBound(NumericItems) = -1 Then Exit Function ' No parameters
Dim vVal As Variant, vNumeric As Variant
vVal = NumericItems(0)
For Each vNumeric In NumericItems
vVal = IIf(vNumeric < vVal, vNumeric, vVal) ' Keep smaller of 2 values
Next
f_var_Min = vVal ' Return final value
End Function
Function f_var_Max(ParamArray NumericItems()) As Variant
If UBound(NumericItems) = -1 Then Exit Function ' No parameters
Dim vVal As Variant, vNumeric As Variant
vVal = NumericItems(0)
For Each vNumeric In NumericItems
vVal = IIf(vNumeric < vVal, vVal, vNumeric) ' Keep larger of 2 values
Next
f_var_Max = vVal ' Return final value
End Function
这两个函数之间的唯一区别是 IIF 语句中 vVal 和 vNumeric 的顺序。
for each 子句使用内部 VBA 逻辑来处理循环和数组边界检查,而“Base 0”从 0 开始数组索引。
这两个函数都存在 Null 问题。我认为这会更好。
Public Function iMin(ParamArray p()) As Variant
Dim vVal As Variant, vMinVal As Variant
vMinVal = Null
For Each vVal In p
If Not IsNull(vVal) And (IsNull(vMinVal) Or (vVal < vMinVal)) Then _
vMinVal = vVal
Next
iMin = vMinVal
End Function
您可以在 Access VBA 中调用 Excel 函数:
Global gObjExcel As Excel.Application
Public Sub initXL()
Set gObjExcel = New Excel.Application
End Sub
Public Sub killXL()
gObjExcel.Quit
Set gObjExcel = Nothing
End Sub
Public Function xlMax(a As Double, b As Double) As Double
xlCeiling = gObjExcel.Application.Max(a, b)
End Function
您可以在 Access VBA中执行Worksheetfunction.max()
或操作。worksheetfunction.min()
希望这可以帮助。