使用Recordset.Find报错:Rowset不支持向后滚动(存储过程场景)
解决「Rowset does not support scrolling backward」错误的几种方案
首先,你遇到的这个错误核心原因是:sp_fkeys这类系统存储过程默认返回的是仅向前游标(forward-only),即使你指定了adOpenDynamic,在服务器端游标(adUseServer)模式下,ADODB也无法修改这个游标的属性——因为游标是由数据库服务器创建并控制的,它不支持向后滚动,自然就没法用Find方法(Find需要游标能自由移动)。
下面是几个可行的解决办法:
方案1:切换到客户端游标(最直接的修复)
把游标位置改成客户端游标(adUseClient),这样游标会在本地内存中创建,支持所有游标类型和Find方法。修改后的代码如下:
Private Sub maintablebox_Change() Dim cnn As ADODB.Connection Dim keys As ADODB.Recordset Set cnn = New ADODB.Connection connstring = "omitted" cnn.Open connstring Set keys = New ADODB.Recordset ' 改成客户端游标 keys.CursorLocation = adUseClient query = "EXEC sp_fkeys @fktable_name = 'astAssets'" ' 这里可以保留adOpenDynamic,或者用adOpenStatic也可以 keys.Open query, cnn, adOpenDynamic, adLockReadOnly ' 现在Find应该可以正常运行了 keys.Find "PKTABLE_NAME = 'astAssetTypes'" If Not keys.EOF Then Debug.Print keys.Fields("FKCOLUMN_NAME") Else Debug.Print "未找到匹配的记录" End If ' 记得关闭对象 keys.Close cnn.Close Set keys = Nothing Set cnn = Nothing End Sub
注意:客户端游标会把整个记录集加载到本地内存,适合数据量不大的场景,你的
sp_fkeys返回的键信息通常数据量很小,完全没问题。
方案2:直接在查询中过滤(更高效)
既然你要找特定PKTABLE_NAME的记录,不如直接在查询阶段就过滤掉不需要的数据,避免后续用Find处理。可以把sp_fkeys的结果插入临时表,再查询临时表:
Private Sub maintablebox_Change() Dim cnn As ADODB.Connection Dim keys As ADODB.Recordset Set cnn = New ADODB.Connection connstring = "omitted" cnn.Open connstring Set keys = New ADODB.Recordset ' 先把sp_fkeys的结果存到临时表,再查询过滤 query = "CREATE TABLE #TempKeys (" & _ "PKTABLE_QUALIFIER VARCHAR(128), PKTABLE_OWNER VARCHAR(128), PKTABLE_NAME VARCHAR(128), " & _ "PKCOLUMN_NAME VARCHAR(128), FKTABLE_QUALIFIER VARCHAR(128), FKTABLE_OWNER VARCHAR(128), " & _ "FKTABLE_NAME VARCHAR(128), FKCOLUMN_NAME VARCHAR(128), KEY_SEQ INT, UPDATE_RULE INT, " & _ "DELETE_RULE INT, FK_NAME VARCHAR(128), PK_NAME VARCHAR(128), DEFERRABILITY INT);" & _ "INSERT INTO #TempKeys EXEC sp_fkeys @fktable_name = 'astAssets';" & _ "SELECT FKCOLUMN_NAME FROM #TempKeys WHERE PKTABLE_NAME = 'astAssetTypes';" ' 这里用默认的仅向前游标就行,因为只需要一条结果 keys.Open query, cnn, adOpenForwardOnly, adLockReadOnly If Not keys.EOF Then Debug.Print keys.Fields("FKCOLUMN_NAME") Else Debug.Print "未找到匹配的记录" End If keys.Close cnn.Close Set keys = Nothing Set cnn = Nothing End Sub
这个方案不需要修改游标类型,而且更高效,因为数据库直接帮你过滤了数据,不用把所有记录加载到客户端。
方案3:手动遍历记录集替代Find
如果因为某些原因不能改游标或查询,你可以手动遍历记录集来找到目标记录:
Private Sub maintablebox_Change() Dim cnn As ADODB.Connection Dim keys As ADODB.Recordset Dim found As Boolean Set cnn = New ADODB.Connection connstring = "omitted" cnn.Open connstring Set keys = New ADODB.Recordset keys.CursorLocation = adUseServer query = "EXEC sp_fkeys @fktable_name = 'astAssets'" keys.Open query, cnn, adOpenForwardOnly, adLockReadOnly found = False Do While Not keys.EOF If keys.Fields("PKTABLE_NAME").Value = "astAssetTypes" Then Debug.Print keys.Fields("FKCOLUMN_NAME") found = True Exit Do End If keys.MoveNext Loop If Not found Then Debug.Print "未找到匹配的记录" End If keys.Close cnn.Close Set keys = Nothing Set cnn = Nothing End Sub
这个方法用仅向前游标遍历,虽然代码多一点,但完全避免了滚动的问题。
内容的提问来源于stack exchange,提问作者Tim Stack
相关产品推荐
相关产品推荐

