locked
MAX Function RRS feed

  • Question

  • I am trying to get the Max value of a column and this is not working.  Can someone plz help?  The code is as follows:

           Set rstDlrVehiclesFnd = db.OpenRecordset("SELECT MAX(tblDlrVehicles.MsrpNoShipping)  FROM tblDlrVehicles WHERE Model = '" & strModel & "' AND MakeCar = '" & strMake & "' AND YearCar = " & lngYearCar & " ORDER BY MakeCar, YearCar, Model;", dbOpenDynaset).

      I am getting a 3122 error when I use this code.  Yet this code is just fine.

            Set rstDlrVehiclesFnd = db.OpenRecordset("SELECT tblDlrVehicles.MsrpNoShipping  FROM tblDlrVehicles WHERE Model = '" & strModel & "' AND MakeCar = '" & strMake & "' AND YearCar = " & lngYearCar & " ORDER BY MakeCar, YearCar, Model;", dbOpenDynaset)

    Any assistance would be great!

    Wednesday, April 29, 2020 7:57 PM

Answers

  • Why not just call the DMax function?

    Dim strModel  As String
    Dim MakeCar  As String
    Dim strCriteria As String
    Dim lngYearCar As Long
    Dim curMaxValue As Currency

    ' get values of strModel, strMake and lngYearCar from somewhere

    strCriteria = "Model = """ & strModel & """ And " & _
        "MakeCar = """ & strMake & """ And " & _
        "YearCar  = " & lngYearCar

    curMaxValue  = DMax("MsrpNoShipping", "tblDlrVehicles", strCriteria)

    Benchmarking has generally shown that, to return a single value, calling a domain function is more efficient than establishing a recordset object.


    Ken Sheridan, Stafford, England


    • Edited by Ken Sheridan Wednesday, April 29, 2020 10:19 PM Typo corrected.
    • Marked as answer by ballj_351 Wednesday, April 29, 2020 11:55 PM
    Wednesday, April 29, 2020 10:15 PM

All replies

  • Take off the "ORDER BY..." part.  This code should only return a single row anyway.

    -Bruce


    Wednesday, April 29, 2020 8:36 PM
  • This fixed me getting the record, yet I am not getting the value.  Looked at several links online and I am not seeing why I am not getting the value.  It is taking the correct path, but the value for intCarCnt is empty!

    The code is as follows now:

                

            Set rstDlrVehiclesFnd = db.OpenRecordset("SELECT MAX(tblDlrVehicles.CarCnt) as intCarCnt FROM tblDlrVehicles WHERE Model = '" & strModel & "' AND MakeCar = '" & strMake & "' AND YearCar = " & lngYearCar & ";", dbOpenDynaset)

            If rstDlrVehiclesFnd.BOF And rstDlrVehiclesFnd.EOF Then
                cntVehicle = 1
            Else
                cntVehicle = intCarCnt + 1
            End If

    It *.BOF and *.EOF are both false, which is what I expected, but when I look at intCarCnt  it shows as 'empty" when I watch it.  I am not getting what I am doing wrong.  Can someone see it?

    Wednesday, April 29, 2020 9:13 PM
  • In the code you've given, intCarCnt is an implicitly declared variant (a variable you probably did not mean to declare).  What you probably meant to refer to in your code is the value of the field intCarCnt, i.e:

     If rstDlrVehiclesFnd.BOF And rstDlrVehiclesFnd.EOF Then
                cntVehicle = 1
            Else
                cntVehicle = rstDlrVehicles!intCarCnt + 1 ' or alternatively rstDlrVehicles.Fields("intCarCnt")
            End If

    To avoid this sort of confusion add "Option Explicit" at the beginning of your code module (look up "Option Explicit Statement" in VBA help)

    -Bruce

    Wednesday, April 29, 2020 9:26 PM
  •        Set rstDlrVehiclesFnd = db.OpenRecordset("SELECT MAX(tblDlrVehicles.MsrpNoShipping)  FROM tblDlrVehicles WHERE Model = '" & strModel & "' AND MakeCar = '" & strMake & "' AND YearCar = " & lngYearCar & " ORDER BY MakeCar, YearCar, Model;", dbOpenDynaset).

    Hi ballj,

    To "see" that MAX-value you could use something like:

    Max_value = db.OpenRecordset("SELECT MAX(tblDlrVehicles.MsrpNoShipping) AS Max_shipping FROM tblDlrVehicles WHERE Model = '" & strModel & "' AND MakeCar = '" & strMake & "' AND YearCar= " & lngYearCar, dbOpenDynaset)!Max_shipping

    Imb.


    • Edited by Imb-hb Wednesday, April 29, 2020 9:41 PM
    Wednesday, April 29, 2020 9:38 PM
  • Why not just call the DMax function?

    Dim strModel  As String
    Dim MakeCar  As String
    Dim strCriteria As String
    Dim lngYearCar As Long
    Dim curMaxValue As Currency

    ' get values of strModel, strMake and lngYearCar from somewhere

    strCriteria = "Model = """ & strModel & """ And " & _
        "MakeCar = """ & strMake & """ And " & _
        "YearCar  = " & lngYearCar

    curMaxValue  = DMax("MsrpNoShipping", "tblDlrVehicles", strCriteria)

    Benchmarking has generally shown that, to return a single value, calling a domain function is more efficient than establishing a recordset object.


    Ken Sheridan, Stafford, England


    • Edited by Ken Sheridan Wednesday, April 29, 2020 10:19 PM Typo corrected.
    • Marked as answer by ballj_351 Wednesday, April 29, 2020 11:55 PM
    Wednesday, April 29, 2020 10:15 PM
  • Everyone,

      I appreciate your responses and answers to my question.  I testes each of them and I must say, they all work!  I went with the one from Ken, based on his comment at the end, since I am modifying this system and I want it to be as efficient as I can.  Thanx everyone and I have learned how to do things better.

    Jerry

    Wednesday, April 29, 2020 11:57 PM
  • It's always been my understanding that the inverse of this is true, i.e. that generating a recordset was generally more efficient than using the domain aggregate functions.  I know this was true in "the old days" of Access 97 where lots of people wrote their own replacements for domain aggregate functions but I think that the gap has narrowed enough for the generic case that using the D* functions is perfectly adequate.  Recent benchmarks I've seen (mostly for DCount()) still indicate that generating a recordset of some sort is still most efficient but not enough to matter.  To be completely sure about specific situations and if performance really matters one should test and compare different methods to see what is most efficient and fits best.  Using domain aggregate functions certainly results in less code and less cleanup.  This in and of itself carries a lot of value and to my mind puts Ken's solution at the top.

    -Bruce

    Thursday, April 30, 2020 3:16 PM
  • Benchmarking has generally shown that, to return a single value, calling a domain function is more efficient than establishing a recordset object.

    Hi all,

    I was triggered by the above remark, because - as Bruce - I had an opposite opinion.

    So I did a little "benchmarking" an a mediate complicated query. In this query the sequencenumber of the children of a father are analysed for the highest number that is a son. The population consist of about 13,000 people.

    I compared three different methods:
    1. result = DMax(…)
    2. result = CurrentDB.OpenRecordset(sql_string)!Max_nr
    3, cur_set = CurrentDB.OpenRecordset(sql_string)
        result = cur_set!Max_nr
        cur_set.Close

    For this test I used the following code:

    Sub Snelheid()
      Dim time1 As Date
      Dim time2 As Date
      Dim time3 As Date
      Dim diff1 As Integer
      Dim diff2 As Integer
      Dim diff3 As Integer
      Dim cur_set As Recordset
      
      Dim aantal As Integer
      Dim x As Integer
      
    'glo_stop
      aantal = 2000
      
      time1 = Now
      For x = 1 To aantal
        jan = DMax("Volgnummer_vader", "Persoon_tbl", "Geslacht = 'M'")
      Next
      time2 = Now
      diff1 = 86400 * time2 - 86400 * time1
       
      time1 = Now
      For x = 1 To aantal
        jan = CurrentDb.OpenRecordset("SELECT MAX(Volgnummer_vader) AS Max_nr FROM Persoon_tbl WHERE Geslacht = 'M'")!Max_nr
      Next
      time2 = Now
      diff2 = 86400 * time2 - 86400 * time1
      
      time1 = Now
      For x = 1 To aantal
        Set cur_set = CurrentDb.OpenRecordset("SELECT MAX(Volgnummer_vader) AS Max_nr FROM Persoon_tbl WHERE Geslacht = 'M'")
        jan = cur_set!Max_nr
        cur_set.Close
      Next
      time2 = Now
      diff3 = 86400 * time2 - 86400 * time1
      
      Msg_form1 "X", diff1, diff2, diff3
      
    End Sub

    The result in seconds is (btw the Max_nr seemed to be 17 in this dataset):

    From this result Method 1 is less efficient by about 10%.

    Method 3 takes a little additional time for "extra code and extra cleanup".

    So - in this example - the most efficient way is method 2.

    Imb.


    • Edited by Imb-hb Thursday, April 30, 2020 6:18 PM
    Thursday, April 30, 2020 6:17 PM
  • Hello Imb-hb,

    This is quite an interesting academic exercise.  I am curious if replacing CurrentDb with DBEngine(0)(0) has a noticeable effect (should be somewhat faster for methods 2 and 3) and if using DBEngine(0)(0).OpenRecordset(sql, dbOpenForwardOnly, dbReadonly) has any effect.

    -Bruce

    Friday, May 1, 2020 6:01 PM
  • This is quite an interesting academic exercise.  I am curious if replacing CurrentDb with DBEngine(0)(0) has a noticeable effect (should be somewhat faster for methods 2 and 3) and if using DBEngine(0)(0).OpenRecordset(sql, dbOpenForwardOnly, dbReadonly) has any effect.

    Hi Bruce,

    I added a 4th method, a copy of method 2, where I replaced  CurrenDb  with  DBEngine(0)(0).

    Results:

    So, using DBEngine(0)(0) is a valid syntax, and runs marginally faster; DMax still uses about 10% more time.

    I am still in favour of:    CurrentDb.Openrecordset(sql_string)!My_field. This perfectly fits in my way of working where I generate dynamically the sql_strings to be used in generalized forms.

    Imb.

    Friday, May 1, 2020 7:10 PM
  • Interesting.  Thanks for taking the time to benchmark this!

    -Bruce

    Friday, May 1, 2020 9:04 PM
  • Interesting.  Thanks for taking the time to benchmark this!

    Hi Bruce,

    In a new test I also added method 5 with the parameters    dbOpenForwardOnly, dbReadonly    to the OpenRecordset.

    This had hardly any effect on the total time. In fact it increased the time! I think this is an artefact of the measurement. The recordset returns only one record, and it does not make much difference if that one record is readonly or not.

    Further, the processing time of all 5 methods takes about 5 minutes. In that time there is, without doubt, an influence of other processes running in the background with respect to the availability of CPU.

    Imb.

    Friday, May 1, 2020 9:23 PM
  • Hi Bruce,

    I ran a few more cycles to get an idea of the reproducability.

    For the methods 1 to 5 this is:

    65 - 59 - 59 - 59 - 62
    65 - 59 - 59 - 59 - 62
    65 - 59 - 59 - 58 - 63

    The methods 2, 3 and 4 are comparable efficient, the methods 1 and 5 are consistently less efficient.

    Imb.

    Saturday, May 2, 2020 10:35 AM