Reputation: 1726
Alright, here's an odd one from an MS Access database I'm running.
I have a SQL query:
SELECT *
FROM [Service Schedule]
WHERE ID=2
AND Volume <= 3000
AND Term='Monthly'
AND special = 'Regular'
ORDER BY volume
When I put that into the SQL view of the query builder, I get 2 records, one with a volume of 0 and one with a volume of 3000.
When I use this code:
sSQL = "SELECT * FROM [Service Schedule] WHERE ID=2 AND Volume <= 3000 AND Term='Monthly' and special = 'Regular' ORDER BY volume"
Set rsServiceSched = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)
** To see what I'm getting from the query in the code, I'm using Debug.Print to output the recordcount and the volume.
I only get 1 record, the one with the volume of 0.
Here's where it gets really strange...
When I change Volume <= 3000 to Volume < 3000 I get one record (volume = 0)
When I change Volume <= 3000 to Volume = 3000 I get one record (volume = 3000)
Anyone spot anything blatantly wrong with what I'm doing?
Upvotes: 0
Views: 737
Reputation: 23067
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.
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.
Upvotes: 4
Reputation: 8053
This is DAO, you need to movelast to get the full recordcount; otherwise, you'll just get 1 if records exist and 0 if they do not.
Upvotes: -2
Reputation: 2042
You are probably not looping through your result set. rsServiceSched is merely pointing to the first record, which will be the one with the lowest volume (bacuase of your order by clause). Now you need to do something with that, then advance to the next record
This example might help you...
Upvotes: 0
Reputation: 1506
It sounds like you are expecting to 'see' all of the records, but I think you are just retrieving the first record. I say this because you are seeing what would be the first record with each case. You will probably need to move to the next record in your recordset in order to see the next one.
rsServiceSched.MoveNext
Upvotes: 1
Reputation: 2006
I'm not sure what you're doing for PK values of that table but when you say: "ID=2" that sounds fishy to me because I always use surrogate keys (never natural) and ID is always the PK. Since you aren't joining to any tables this tells me you should always expect one row/tuple from your result.
If ID isn't your PK would you mind letting me know via the comments?
Perhaps you need to iterate over the result set using: Set.MoveNext
Upvotes: 1