Custom Search
 


Use VBA to get the correct number of records in a Recordset object



Does your Recordset return -1 for its RecordCount property? If yes, this article will be able to help you and explain the cause and fixes.

If you have used Microsoft ADO in your VBA project, you must have used Recordset object. Recordset is just a temporary table in memory that contains rows and columns of data. You can navigate through the recordset and do whatever processing you are legit to do.

Recordset object has a RecordCount property that indicates how many records in the Recordset. When I first used ADO in 1999, it had puzzled me for over a year why the RecordCount always returned -1. After many tests and digs into the Help document, I realized the culprit was the type of cursor I used for the record set.

By default, ADO implicitly creates a forward only cursor for a recordset and returns -1 in the RecordCount property when one of the following methods is used.

  1. When opening the recordset object by using the Open method of the Recordset object if no cursor type is specified.
  2. When obtaining the Recordset object by using the Execute method of the Connection object. This method does not give us the option to specify cursor type.

The first two code examples below demonstrate how to create recordset with forward only cursor. Then two more examples are given to show how to create recordsets that return the valid record count.

To get the code on this page to work, you need to add a reference to Microsoft ActiveX Data Objects Library (any version from 2.0 to 2.8) in Northwind database.

In VBA editor, click Tools -> References...

How to create Recordset that returns -1 on the RecordCount property

The following two code snippets implicitly create forward only cursor and will return -1 on the RecordCount property.

To see how the code below works, in Access Northwind database, create a form with two buttons and name them as cmdCnnExecute and cmdRstOpen. Copy the code into their relevant On Click event procedure.

(1) Use Execute method of the Connection object - RecordCount returns -1.

The Execute method returns a recordset with forward only cursor type.

Private Sub cmdCnnExecute_Click()
    On Error Goto Catch

    Dim strSql As String
    Dim objCnn As ADODB.Connection
    Dim objRst As ADODB.Recordset
    
    '' Get all categories
    strSql = "select CategoryID, CategoryName from Categories"
    
    Set objCnn = CurrentProject.Connection
    Set objRst = New ADODB.Recordset
    
    '' This implicitly creates a recordset object with forward only cursor by default.
    Set objRst = objCnn.Execute(strSql)

    '' Display the number of records in Immediate window. Returns -1    
    Debug.Print "objRst (adOpenForwardOnly) record count: " & objRst.RecordCount
                
    '' Clean up
    Set objCnn = Nothing    
    objRst.Close
    Set objRst = Nothing
        
    Exit Sub
    
Catch:
    MsgBox "cmdRecordCount_Click(): " & vbCrLf & vbCrLf _
            & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description
End Sub

(2) Use Open method of the Recordset object with default cursor type - RecordCount returns -1.

In this example, the Open method creates a recordset of a forward only cursor type. This is because the cursor type argument is omitted in the method, so the default argument adOpenForwardOnly is used.

Private Sub cmdRstOpen_Click()
    On Error Goto Catch

    Dim strSql As String
    Dim objRst As ADODB.Recordset
    
    '' Get all categories
    strSql = "select CategoryID, CategoryName from Categories"
        
    Set objRst = New ADODB.Recordset
    
    '' This creates a recordset object with forward only cursor by default because
    '' we didn't specify the cursor type enum.
    objRst.Open strSql, CurrentProject.Connection
            
    '' Display the number of records in Immediate window. 
    '' Returns -1
    Debug.Print "objRst (adOpenForwardOnly) record count: " & objRst.RecordCount

    '' Clean up
    objRst.Close
    Set objRst = Nothing
        
    Exit Sub
    
Catch:
    MsgBox "cmdRecordCount_Click(): " & vbCrLf & vbCrLf _
           & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description
End Sub

The ways to obtain a valid count

Now we're going to look at how to get the correct count by using RecordCount property.

(1) Client-side cursor

When a recordset's cursor location is specified as client-side, it always returns the valid count for RecordCount property.

Client-side cursor is specified in VBA as below.

objRst.CursorLocation = adUseClient

When a recordset is client-side, after it's retrieved from the database server (eg. Oracle, MySQL database server, etc.), it's sent to the client tier (eg. your workstation PC for MS Access application, or web server for an internet application) and made disconnected from the database server, so it's static in nature. Any changes in the database after the retrieval won't affect the data in the recordset.

Please note that, for local Access database, the server and client are on the same machine because server is your Access Jet engine and client is your VBA engine.

(2) Server-side Static or Keyset cursor.

When a recordset is opened, by default it's opened as a server-side, forward only cursor. If we change its cursor type to static or keyset cursor, it will return the valid count for RecordCount property.

The following code opens a static cursor.

objRst.CursorType = adOpenStatic

'' Or specify adOpenStatic in the Open method directly.
objRst.Open strSql, CurrentProject.Connection, adOpenStatic

The following code opens a keyset cursor.

objRst.CursorType = adOpenKeyset

'' Or specify adOpenKeyset in the Open method directly.
objRst.Open strSql, CurrentProject.Connection, adOpenKeyset

To understand more about the pros and cons for client-side and server-side cursor, refer to Microsoft article Client-Side Cursors Versus Server-Side Cursors.

Example of client-side cursor that returns actual count

Code below shows how a client-side cursor returns the actual record count. In Northwind database, on the form you are using for testing, create a new button named cmdRecordCountClientSide, then copy the code below in its On Click event.

Private Sub cmdRecordCountClientSide_Click()
    On Error Goto Catch

    Dim strSql As String
    Dim objRst As ADODB.Recordset
    
    '' Get all categories from local Northwind database.
    strSql = "select CategoryID, CategoryName from Categories"
    
    Set objRst = New ADODB.Recordset

    '' Client-side cursor
    objRst.CursorLocation = adUseClient
    
    objRst.Open strSql, CurrentProject.Connection
    
    '' Returns the actual count (8 records)
    Debug.Print "Client-side objRst record count: " & objRst.RecordCount

    '' Clean up
    objRst.Close
    Set objRst = Nothing
        
    Exit Sub
    
Catch:
    MsgBox "cmdRecordCount_Click()" & vbCrLf & vbCrLf _
           & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description
End Sub

Immediate Window shows the actual count for client-side cursor.

Example of all four server-side cursor types

Code below shows four recordsets with four different cursor types. Static and keyset cursor return the actual count. Forward only and dynamic cursor return -1. Because we didn't specify cursor location, it defaults to server-side. On the other hand, because the records are retrieved from local Access Northwind database, the client-side and server-side are both on the local computer.

In Northwind database, on the form you are using for testing, create a new button named cmdRecordCount, then copy the code below in its On Click event.

Private Sub cmdRecordCount_Click()
    On Error Goto Catch

    Dim strSql As String
    Dim objRst1 As ADODB.Recordset
    Dim objRst2 As ADODB.Recordset
    Dim objRst3 As ADODB.Recordset
    Dim objRst4 As ADODB.Recordset

    '' Get all categories from local Northwind database.
    strSql = "select CategoryID, CategoryName from Categories"
    
    '' In code below, because we didn't specify cursor location, it's server-side by default.
    
    '' Returns -1
    Set objRst1 = New ADODB.Recordset
    objRst1.Open strSql, CurrentProject.Connection, adOpenForwardOnly

    '' Returns -1
    Set objRst2 = New ADODB.Recordset
    objRst2.Open strSql, CurrentProject.Connection, adOpenDynamic

    '' Returns valid count
    Set objRst3 = New ADODB.Recordset
    objRst3.Open strSql, CurrentProject.Connection, adOpenKeyset

    '' Returns valid count
    Set objRst4 = New ADODB.Recordset
    objRst4.Open strSql, CurrentProject.Connection, adOpenStatic
        
    '' Display the number of records in Immediate window.
    Debug.Print "objRst1 (adOpenForwardOnly) record count: " & objRst1.RecordCount
    Debug.Print "objRst2 (adOpenDynamic) record count: " & objRst2.RecordCount
    Debug.Print "objRst3 (adOpenKeyset) record count: " & objRst3.RecordCount
    Debug.Print "objRst4 (adOpenStatic) record count: " & objRst4.RecordCount

    '' Clean up
    objRst1.Close
    objRst2.Close
    objRst3.Close
    objRst4.Close
    Set objRst1 = Nothing
    Set objRst2 = Nothing
    Set objRst3 = Nothing
    Set objRst4 = Nothing
        
    Exit Sub
    
Catch:
    MsgBox "cmdRecordCount_Click()" & vbCrLf & vbCrLf _
           & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description
End Sub

Immediate Window shows four values.

Please note:

(1) If you're (in rare situations) using a static cursor or keyset cursor but still get -1, specifying lock type as adLockOptimistic may fix your problem.

(2) If a dynamic cursor is specified, we may get either -1 or the actual count depending on the circumstances, but forward only cursor always returns -1.

Happy Coding!


Copyright© GeeksEngine.com



Other Recent Articles from the MS Access category:

1. Examples of MS Access DateDiff function used in query and VBA code
2. MS Access DateDiff function
3. How to find out your computer name and username by VBA
4. Examples of MS Access DatePart function
5. MS Access DatePart function
6. Examples of MS Access DateAdd function
7. MS Access DateAdd function
8. IIF function basics - the CASE statement of MS Access
9. MS Access Date Expression
10. Solved: MS Access error "The text is too long to be edited"
11. Create MS Access Combo Box essential properties by VBA code
12. Create MS Access Combo Box essential properties manually
13. How to do text search in MS Access programmatically
14. Solved - the size of the Access query result is larger than the maximum size of a database (2 GB)
15. How to easily get a list of field names in MS Access
16. How to count distinct records in MS Access
17. How to do transaction based processing in MS Access
18. How to open a document (local/network file or web page) from MS Access
19. How to use ADOX to create unique composite index - the VBA approach
20. How to do cross-table update queries in MS Access - the right way
21. Three efficient ways to get the number of records by using VBA
22. How to create a composite unique index (not as a primary key) in MS Access
23. Disable Access Prompt when a record is changed, table deleted, or action queries run
24. How to hide and unhide a MS Access object
25. How to return multiple values from a VBA function (Part 3)
26. How to return multiple values from a VBA function (Part 2)
27. How to return multiple values from a VBA function (Part 1)
28. Three ways to programmatically duplicate a table in MS Access by VBA
29. Create a DLL by CSharp or VB.Net for VBA
30. How to correctly reference and call a DLL
31. How to register a C# or VB.Net DLL
32. Email address validation by Regular Expressions using VBA
33. Fix MS Access error: Query must have at least one destination field
34. How to unselect radio buttons in MS Access after it has been selected
35. How to Change Query Timeout Value for MS Access SQL Queries
36. What is Northwind Traders database

Copyright © 2024 GeeksEngine.com. All Rights Reserved.

This website is hosted by HostGator.

No portion may be reproduced without my written permission. Software and hardware names mentioned on this site are registered trademarks of their respective companies. Should any right be infringed, it is totally unintentional. Drop me an email and I will promptly and gladly rectify it.

 
Home | Feedback | Terms of Use | Privacy Policy


聚圣源起名姓王姑娘名字洋气合唱团起名大全集霸气移动藏经阁起名手稿永字起名缔造者名字孙姓婴儿起名大全男孩工程建设公司起名大全带树字起名qq等级图兰朵电影马起名字大全女孩名字五岳独尊军少的小甜心女孩刘姓鼠年起名大全论语十则原文及翻译盈字起名吉凶起名字2021免费八字起名男起姓男孩名字大全打分测免费免费在线名字大全起名姓宁姑娘起名字美梦神家庭农场起个什么名字好bd什么意思昆明起名大师装修起名字叫什么好psp零之轨迹新年的诗句免费起名字测试打分100相框素材淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻让美丽中国“从细节出发”清明节放假3天调休1天男孩疑遭霸凌 家长讨说法被踢出群国产伟哥去年销售近13亿网友建议重庆地铁不准乘客携带菜筐雅江山火三名扑火人员牺牲系谣言代拍被何赛飞拿着魔杖追着打月嫂回应掌掴婴儿是在赶虫子山西高速一大巴发生事故 已致13死高中生被打伤下体休学 邯郸通报李梦为奥运任务婉拒WNBA邀请19岁小伙救下5人后溺亡 多方发声王树国3次鞠躬告别西交大师生单亲妈妈陷入热恋 14岁儿子报警315晚会后胖东来又人满为患了倪萍分享减重40斤方法王楚钦登顶三项第一今日春分两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?周杰伦一审败诉网易房客欠租失踪 房东直发愁男子持台球杆殴打2名女店员被抓男子被猫抓伤后确诊“猫抓病”“重生之我在北大当嫡校长”槽头肉企业被曝光前生意红火男孩8年未见母亲被告知被遗忘恒大被罚41.75亿到底怎么缴网友洛杉矶偶遇贾玲杨倩无缘巴黎奥运张立群任西安交通大学校长黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发妈妈回应孩子在校撞护栏坠楼考生莫言也上北大硕士复试名单了韩国首次吊销离岗医生执照奥巴马现身唐宁街 黑色着装引猜测沈阳一轿车冲入人行道致3死2伤阿根廷将发行1万与2万面值的纸币外国人感慨凌晨的中国很安全男子被流浪猫绊倒 投喂者赔24万手机成瘾是影响睡眠质量重要因素春分“立蛋”成功率更高?胖东来员工每周单休无小长假“开封王婆”爆火:促成四五十对专家建议不必谈骨泥色变浙江一高校内汽车冲撞行人 多人受伤许家印被限制高消费

聚圣源 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化