处理多 RDO 结果集

任何 SQL 语句都可能包括多个 SELECT 语句或存储过程,后者又可能调用一个或多个 SELECT 语句。每一个 SELECT 语句产生一个结果集,它必须由代码进行处理,或者在 RDO 资源被释放,并且下一个结果集成为可用的之前被放弃。

动作查询也会产生无数据行的结果集,这也是必须处理的,因为这是多结果集查询的另一种类型。在很多时候,执行一个存储过程可能会返回多个结果集。存储过程是否会返回多个结果集往往很难确定,因为存储过程可能调用了另一个过程。

例如,假设提交了一个查询,其中包括四个 SELECT 查询,用来置入到四个本地的 ListBox 控件,还包括一个事件过程,用来更新表,那么代码至少需要处理五个结果集。因为不知道会存储过程会产生多少个结果集,因此代码也就必须准备处理 n 个结果集。

执行多结果集的查询有两种方法:

这两种方法处理都很相似,但如果使用 rdoQuery 的话,可以检查 RowsAffected 属性以确定动作查询影响的数据行数。虽然也可以使用 Execute 方法执行多结果集查询,但却不能获取被单个语句影响的那些数据行,如果有的查询返回了数据行,将导致一个可以捕获的错误。

使用服务器端的游标库处理多结果集

并非所有的游标驱动程序都支持对多结果集查询的处理。SQL Server 服务器端的游标驱动程序就是这样的一个例子。但是,如果使用 rdOpenForwardOnly、rdConcurReadOnly 选项,并将 RowsetSize 属性设为 1,即可请求建立一个无游标结果集,这样就可以使用服务器端的游标来执行多结果集查询。将 CursorDriver 属性设为 rdUseNone 也可为所有结果集设置这些选项。

多结果集:一个示例

本节将分步讲解使用 rdoQuery 对象来执行多结果集查询的步骤。

提示   在使用连接符 "&" 建立 SQL 查询时,运算符之间一定要有空格(可以用空格键或 TAB 键)。

  1. 创建 SQL 语句,并将其放到一个字符串变量中,如 MySQL。对于 SQL Server,多个语句之间必须用分号分开。
    Dim MySQL As String
    MySQL = "Select Name from Authors Where ID = 5; " _
    & " Select City from Publishers; " _
    & " Update MyTable " _
    & " Set Age = 18 Where Name = 'Fred'"
    
  2. 然后,创建一个新的 rdoQuery ,并设置一个声明为 rdoQuery 类和多结果集的变量到该对象,在这个例子中是 MyQy。本例假定 rdoConnection 对象 (Cn) 已经存在。有许多方法可以实例化和初始化 rdoQuery 对象,这里只介绍了其中的一种。
    Dim MyQy As rdoQuery
    Set MyQy = Cn.CreateQuery("MyQy1", "")
    MyQy.SQL = MySQL
    
  3. 对 rdoQuery 对象使用 OpenResultset 方法执行该查询。如果不需要将特别的属性和功能传递到该查询,那么可以直接使用 rdoConnection 对象的 OpenResultset 方法。所用的参数会影响到查询产生的全部结果集。例如,如果需要在第二个结果集中使用游标,则必须在断开第一个结果集之后指定游标类型。
    Dim MyRs As rdoResultset
    Set MyRs = MyQy.OpenResultset(rdOpenForwardOnly, _
    rdConcurReadOnly)
    
  4. 现在已经准备好了,可以处理第一个结果集了。注意,rdAsyncEnable 选项参数还没有设置。因此,在第一个结果集的第一行准备好之前,控制不会返回到应用程序。如果当前的 rdoResultset 包含数据行,RowCount 属性将被设为一个大于零的值,EOF 和 BOF 属性都是 False。如果未返回数据行,则 RowCount 属性返回 -1 或 0,表明数据行的数目无效,返回 -1 还是 0 由驱动程序和数据源决定。

    下述例子将查询结果填入名为 NameList1 的列表框控件中。

    While Not MyRs.EOF         '循环执行所有的行。
    '使用第一列。
    NameList1.AddItem = MyRs(0)    
    MyRs.MoveNext            '定位到结果集的下一行。
    Wend
    
  5. 第一个结果集已到达文件结尾处 (MyRs.EOF = True)。使用 MoreResults 方法激活下一个。一旦执行了 MoreResults 之后,第一个结果集便不再可用了,即使用游标选项来创建它。
    '激活下一个结果集。
    If (MyRs.MoreResults) Then ...
    
  6. 现在已经准备好处理第二个结果集了。本例只使用了开始的几个名称,并废弃了剩余的数据行。
    '循环若干行。
    Do While Not MyRs.EOF and MyRs(0) < "B"
    '使用第一列。
    NameList1.AddItem = MyRs(0)
    MyRs.MoveNext
    Loop
    '激活下一个结果集,
    '并废弃剩余的数据行。
    If (MyRs.MoreResults) Then ...
    
  7. 现在已经准备好处理最后一个结果集。因为这是一个 UPDATE 语句,没有返回的数据行,但可以通过 RowsAffected 属性确定受到影响的数据行的数目。最后,使用 MoreResults 方法释放与该查询相联的所有资源。
    If MyQy.RowsAffected = 0 Then
    MsgBox "No rows were updated"
    End If
    '激活下一个结果集。
    If (MyRs.MoreResults) Then ...
    

对最后一个结果集使用 MoreResults 方法之后,将返回 False,执行该查询所要求的其它资源也会被释放。这时,rdoQuery 对象可以再次使用。如果对 rdoQuery 使用了 Close 方法,它将从 rdoQueries 集合中删除。