Digression: A discussion of the Recordcount of DAO recordsets
The recordcount of a DAO recordset is not guaranteed accurate until after a .MoveLast, but if any records are returned by the recordset, .RecordCount will be 1 or more.
Note that a table-type recordset will return an accurate .RecordCount immediately, without the .MoveLast, but keep in mind that you can't open a table-type recordset on a linked table. Also, be careful and don't assume you're getting the recordset type you want unless you've explicitly specified it. While dbOpenTable is the default recordset type, if the table or SQL string can't be opened as a table-type recordset, it will fall over to opening a dynaset. Thus, you can think you're opening a table-type recordset with this because table-type is the default and you've passed a table name:
Set rs = CurrentDB.OpenRecordset("MyTable")
but you have to remember that just because you pass it a table, it won't necessarily open a table-type recordset, and the recordcount won't necessarily be accurate. If you really want to be sure you're opening a table-type recordset, you need to specify that explicitly:
Set rs = CurrentDB.OpenRecordset("MyTable", dbOpenTable)
If "MyTable" is a linked table, that will throw an error. If you have a mix of linked tables and local tables, you'll have to use two different methods to obtain a table-type recordset. Otherwise (i.e., if you're not specifying the recordset type and letting it be table-type when possible and a dynaset when not), you need to know when you need to .MoveLast to get an accurate .RecordCount. If you really want to be efficient in that case, you'll test the .Type of the recordset:
Set rs = CurrentDB.OpenRecordset("MyTable")
If rs.Type = dbOpenDynaset Then
rs.MoveLast
End If
At that point, you'll have an accurate .RecordCount property whether the recordset opened as table-type or as a dynaset.
But keep in mind that it's very seldom that you need to use a full recordset to get a recordcount. Usually, you will examine the .RecordCount only to see if your recordset has returned any records, and in that case, you don't need an accurate count.
Likewise, if you're going to walk through the full recordset, you'll eventually have an accurate RecordCount. That is, it would be senseless to do this:
Set rs = CurrentDB.OpenRecordset("MyTable")
rs.MoveLast
If rs.RecordCount > 0 Then
.MoveFirst
Do Until rs.EOF
[something or other]
.MoveNext
Loop
End If
Debug.Print rs.RecordCount
The .MoveLast is completely unneeded in that context as you don't need to know the exact count at that point in the code.
Also, keep in mind that in some contexts where you really do need to know the exact .RecordCount, it may be more efficient to just use the built-in Access DCount() function, or to do something like this:
Dim lngRecordCount As Long
lngRecordCount = CurrentDB.OpenRecordset("SELECT COUNT(*) FROM MyTable")(0)
Or:
lngRecordCount = DBEngine.OpenDatabase(Mid(CurrentDB.TableDefs("MyTable").Connect, 11)).TableDefs("MyTable").RecordCount
There are all sorts of efficient shortcuts to get the accurate RecordCount without forcing the recordset pointer to travel to the last record.
BTW, one of the reason the RecordCount for a pure Table-Type record is accurate is because it doesn't have to be calculated -- Jet/ACE maintains the RecordCount property as part of its regular operations.
Digression: A discussion of the Recordcount of ADO recordsets
By @onedaywhen
For an ADO recordset, the RecordCount
property will always be the final value. That is, unlike DAO, if you check its value it cannot subsequently change. Navigating EOF
does not affect the RecordCount
value in any way for ADO.
This is true even when fetching records asynchronously (something DAO recordsets does not explicitly support): that is, even when the recordset is not yet full, the RecordCount
property still reflects the final value (not the number of records fetched so far, as for DAO).
Some combinations of CursorLocation
and CursorType
will cause RecordCount
to always be -1, meaning the property is not supported. But, again, this will remain constant i.e. if it is initially -1 then it will always be -1.
The applicable combinations for the Access database engine for which RecordCount
is not supported are adOpenForwardOnly
and adOpenDynamic
but only when using a server side cursor location. (Note the Access database engine doesn't actually support dynamic cursors: instead adOpenDynamic
is overloaded for the user to provide an optimization 'hint' to the engine that the recordset's Source
is dynamic SQL code).
Note that setting the recordset's Filter
property will change the RecordCount
to reflect the number of records after the filter has been applied.