No max(x,y) function in Access
Asked Answered
I

8

16

VBA for Access lacks a simple Max(x,y) function to find the mathematical maximum of two or more values. I'm accustomed to having such a function already in the base API coming from other languages such as perl/php/ruby/python etc.

I know it can be done: IIf(x > y, x,y). Are there any other solutions available?

Impetus answered 31/8, 2009 at 2:12 Comment(1)
You could use the Excel functions in Access. (More below.)Ellerd
F
10

I'll interpret the question to read:

How does one implement a function in Access that returns the Max/Min of an array of numbers? Here's the code I use (named "iMax" by analogy with IIf, i.e., "Immediate If"/"Immediate Max"):

  Public Function iMax(ParamArray p()) As Variant
  ' Idea from Trevor Best in Usenet MessageID [email protected]
    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 [email protected]
    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

As to why Access wouldn't implement it, it's not a very common thing to need, seems to me. It's not very "databasy", either. You've already got all the functions you need for finding Max/Min across domain and in sets of rows. It's also not very hard to implement, or to just code as a one-time comparison when you need it.

Maybe the above will help somebody.

Florous answered 10/7, 2011 at 2:12 Comment(4)
That's more useful than down votes a year after the question. :)Impetus
I'm surprised it didn't get an answer sooner, given how trivial the problem is. Perhaps it's because the question was confrontational (i.e., badmouthing Access) so that the people who knew the answer were too turned off to bother to try to help somebody who seems to have something of a chip on his shoulder.Florous
You DO understand why a database development tool wouldn't have such a function built in, right? There are much greater omissions that are database-related than a function like this.Florous
Can anybody point me to a more common solution that takes as function arguments not only array of numbers, but arrays and collections as well?Nimitz
E
4

Calling Excel VBA Functions from MS Access VBA

If you add a reference to Excel (ToolsReferencesMicrosoft Excel x.xx Object Library) then you can use WorksheetFunction to call most Excel worksheet functions, including MAX (which can also be used on arrays).

Examples:

MsgBox WorksheetFunction.Max(42, 1999, 888)

or,

Dim arr(1 To 3) As Long
arr(1) = 42
arr(2) = 1999
arr(3) = 888
MsgBox WorksheetFunction.Max(arr)

The first call takes a second to respond (actually 1.1sec for me), but subsequent calls are much more reasonable (<0.002sec each for me).


Referring to Excel as an object

If you're using a lot of Excel functions in your procedure, you may be able to improve performance further by using an Application object to refer directly to Excel.

For example, this procedure iterates a set of records, repeatedly using Excel's MAX on a Byte Array to determine the "highest" ASCII character of each record.

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
Ellerd answered 14/11, 2018 at 12:26 Comment(0)
I
1

Because they probably thought that you would use DMAX and DMIN or the sql MAX and only working with the database in access?

Im also curious about why.. Its seems like a overkill to have to create a temp-table and add form values to the table and then run a DMAX or MAX-query on the table to get the result...

Ian answered 31/8, 2009 at 2:26 Comment(1)
yeah, and the values I am using are in the database, but in two columns of the same row. It's just not an aggregate Max, but a simple mathematical Max.Impetus
U
1

I've been known to create a small projMax() function just to deal with these. Not that VBA will probably ever be enhanced, but just in case they ever do add a proper Max (and Min) function, it won't conflict with my functions. BTW, the original poster suggests doing IIF... That works, but in my function, I usually throw a couple of Nz()'s to prevent a null from ruining the function.

Ungovernable answered 31/8, 2009 at 10:12 Comment(0)
R
1

I liked DGM's use of the IIF statement and David's use of the For/Next loop, so I am combining them together.

Because VBA in access does not have a strict type checking, I will be using varients to preserve all numerics, integer and decimal, and re-type the return value.

Kudos to HansUP for catching my parameter verification :)
Comments added to make code more friendlier.

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

The only difference between the 2 functions is the order of vVal and vNumeric in the IIF statement.
The for each clause uses internal VBA logic to handle the looping and array bounds checking, while "Base 0" starts the array index at 0.

Rostellum answered 25/9, 2013 at 15:31 Comment(2)
IsNull(NumericItems) will never be True. If you meant to exit the function when called with no arguments, try checking for UBound(NumericItems) = -1Architectural
Good eye, used your suggestions on some sample data and it worked as advertized, keep it up!Rostellum
A
1

Both functions have problems with Null. I think this will be better.

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
Aurthur answered 22/3, 2016 at 8:53 Comment(1)
Thank you for your contribution. Nulls do pop up and it is nice to have them handled.Splendor
P
0

You can call Excel functions in Access VBA:

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
Photometry answered 15/6, 2020 at 14:13 Comment(0)
A
-1

You can do Worksheetfunction.max() or worksheetfunction.min() within Access VBA. Hope this helps.

Arum answered 20/11, 2017 at 17:29 Comment(1)
A tad more information would be helpful, since this can't be used as-is. (I expanded on this below.)Ellerd

© 2022 - 2024 — McMap. All rights reserved.