EA, here's a function that does what you need.
It's like the build-in DAvg() function, but accepts an additional argument
for the TOP number of records you want.
There is also the option to specify the ORDER BY clause so you can eliminate
the duplicates, sort descending, or even get the average based on the most
recent records rather than top values (i.e. the TOP can be applied to a
different field.)
Function EAvg(strExpr As String, strDomain As String, Optional strCriteria
As String, _
Optional lngTop As Long, Optional strOrderBy As String) As Variant
On Error GoTo Err_Error
'Purpose: Extended replacement for DAvg().
'Author: Allen Browne (
[email protected]), November 2006.
'Requires: Access 2000 and later.
'Return: Average of the field in the domain. Null or error.
'Arguments: strExpr = the field name to average.
' strDomain = the table or query to use.
' strCriteria = WHERE clause limiting the records.
' lngTop = TOP number of records to average. (Ignored if
zero or negative.)
' strOrderBy = ORDER BY clause.
'Note: The ORDER BY clause defaults to the expression field DESC if
none is provided.
' However, if there is a tie, Access returns more than the
TOP number specified,
' unless you include the primary key in the ORDER BY
clause. See example below.
'Example: Return the average of the 4 highest quantities in
tblInvoiceDetail:
' EAvg("Quantity", "tblInvoiceDetail",,4, "Quantity DESC,
InvoiceDetailID")
Dim rs As DAO.Recordset
Dim strSql As String
EAvg = Null 'Initialize to null.
If lngTop > 0& Then
strSql = "SELECT Avg(" & strExpr & ") AS TheAverage " & vbCrLf & _
"FROM (SELECT TOP " & lngTop & " " & strExpr & " " & vbCrLf & _
" FROM " & strDomain & " "
If strCriteria <> vbNullString Then
strSql = strSql & vbCrLf & " WHERE (" & strCriteria & ") "
End If
If strOrderBy <> vbNullString Then
strSql = strSql & vbCrLf & " ORDER BY " & strOrderBy & ") AS
MySubquery;"
Else
strSql = strSql & vbCrLf & " ORDER BY " & strExpr & " DESC) AS
MySubquery;"
End If
Else
strSql = "SELECT Avg(" & strExpr & ") AS TheAverage " & vbCrLf & _
"FROM " & strDomain & " "
If strCriteria <> vbNullString Then
strSql = strSql & vbCrLf & "WHERE " & strCriteria
End If
strSql = strSql & ";"
End If
Set rs = DBEngine(0)(0).OpenRecordset(strSql)
If rs.RecordCount > 0& Then
EAvg = rs!TheAverage
End If
rs.Close
Set rs = Nothing
Exit_Handler:
Exit Function
Err_Error:
MsgBox "Error " & Err.Number & ": " & Err.Description, , "EAvg()"
Resume Exit_Handler
End Function