views:

61

answers:

4

I want to access individual records in a classic ADO recordset without enumerating over the entire recordset using .MoveNext. I'm aware of using AbsolutePosition as well as .Filter =. What's the best way?

More Details: I'm likely going to be accessing the recordset several times pulling out individual records that match a list of records in a particular field. For example, I have a recordset with records that have field values ranging from 1 to 100, I might have a separate array containing just {34, 64, 72}, and I want to do something to only the records in the recordset whose IDs are contained in the array.

+1  A: 

I ended up rewriting my answer due to new information, so:

My suggestion is to set the Filter property to what you want, then enumerate through the resulting subset and assign the Bookmark value of each record in the subset to a variable that you can easily match up with the IDs (so you might want to put them in an array in the order that their IDs are in the ID array you mention).

JAB
+1  A: 

If you are using server-side cursors, then the best method depends on the underlying OLE DB provider that you are using. It is quite possible that each access of the record could result in another trip to the server to read the data.

If you can use a client-side cursor, then I suspect that AbsolutePosition will be the best method to move to each record repeatedly. I believe that using a filter with a client-side cursor would require that it spin through each record matching the filter condition.

Mark Wilkins
What guarantee is there that the order of IDs will be ascending, consecutive, and start at 1? If that's not the case, then you'd have to actually find what the ordinal positions of the records you want are before you'd be able to use AbsolutePosition to refer to them, would you not?
JAB
This is all client-side. Absolute position should work for my situation.
Ben McCormack
@JAB: Correct. But the OP said he would access them multiple times. Once found and positions noted via the AbsolutePosition property, it would be quick to go back to them via the same property.
Mark Wilkins
@Mark: Yeah, I just thought of that myself. Doesn't change the fact that you'd have to find the records first, and if you just need the specific records and don't need them in any specific order as long as you can refer to them multiple times it might be better to use a filter to reduce the set to just those records wanted, I think? And also I may have misunderstood your comment about a filter; are you saying that you can't use AbsolutePosition to refer to a record in a filtered recordset?
JAB
@JAB: I believe you can use both properties, but I *think* the absoluteposition is based on the filtered result set. So with a client-side cursor, using both might be inefficient depending on the implementation. Going to the 3rd position in a filtered set likely means it has to go to the top of the unfiltered set and scan through the records applying the filter and then counting the ones that pass the filter. But I do not know how the client-side cursor implements that behavior.
Mark Wilkins
@Mark: I can't find anything that confirms or denies that specifically, but apparently Filter does create a new cursor in the RecordSet, so it's possible that it maps the values of the positions in the filtered set back to the positions in the unfiltered one. Of course, it may not do so anyway. I wish documentation on that kind of stuff were more easily accessible.
JAB
@JAB: I agree that it would be nice to have more of those details. Conceptually, it behaves as if it is a new cursor after the filter is applied, but it's hard to say if it actually creates a new cursor or simply applies the filter to the existing one as necessary. I was assuming the latter, but I don't know. If the assumption is that the average result set will be traversed once after applying a filter, then my guess would be correct. But if it assumes it will be traversed multiple times, it would make more sense to create the new cursor.
Mark Wilkins
@Mark: Well, whether or not it actually creates a new cursor is irrelevant, it seems: going by [this article](http://articles.techrepublic.com.com/5100-10878_11-1045830.html), using Filter is indeed much more efficient than repeated calls to Find, so the most efficient thing short of filtering via SQL query would be setting Filter and then getting the filtered records' Bookmarks, without needing to use AbsolutePosition at all.
JAB
@JAB: Thanks for doing that research. It is good information.
Mark Wilkins
A: 

Use the Filter function on the Recordset object.

rs.Filter = "ID = '" & strID & "'"
dretzlaff17
A: 

I'm using this function all the time

Public Function InitIndexCollection( _
            rs As Recordset, _
            sFld As String, _
            Optional sFld2 As String, _
            Optional sFld3 As String, _
            Optional ByVal HasDuplicates As Boolean) As Collection
    Const FUNC_NAME     As String = "InitIndexCollection"
    Dim oFld            As ADODB.Field
    Dim oFld2           As ADODB.Field
    Dim oFld3           As ADODB.Field

    On Error GoTo EH
    Set InitIndexCollection = New Collection
    If Not IsRecordsetEmpty(rs) Then
        Set oFld = rs.Fields(sFld)
        If LenB(sFld2) <> 0 Then
            Set oFld2 = rs.Fields(sFld2)
        End If
        If LenB(sFld3) <> 0 Then
            Set oFld3 = rs.Fields(sFld3)
        End If
        If HasDuplicates Then
            On Error Resume Next
        End If
        With rs
            If oFld2 Is Nothing Then
                .MoveFirst
                Do While Not .EOF
                    InitIndexCollection.Add .Bookmark, C_Str(oFld.Value)
                    .MoveNext
                Loop
            ElseIf oFld3 Is Nothing Then
                .MoveFirst
                Do While Not .EOF
                    InitIndexCollection.Add .Bookmark, C_Str(oFld.Value) & "#" & C_Str(oFld2.Value)
                    .MoveNext
                Loop
            Else
                .MoveFirst
                Do While Not .EOF
                    InitIndexCollection.Add .Bookmark, C_Str(oFld.Value) & "#" & C_Str(oFld2.Value) & "#" & C_Str(oFld3.Value)
                    .MoveNext
                Loop
            End If
        End With
    End If
    Exit Function
EH:
    RaiseError FUNC_NAME
    Resume Next
End Function
wqw
@wqw Thanks for providing the function. Perhaps you could add why you feel this function is more performant than other methods in accessing a single record in an ADO recordset. That might help put it into context a little.
Ben McCormack
wqw