提取结果数据
ODBC 应用程序具有三个用于提取结果数据的选项。
第一个选项基于 SQLBindCol。在提取结果集之前,应用程序使用 SQLBindCol 将该结果集中的每一列都绑定到某一程序变量。在绑定这些列后,每次在应用程序调用 SQLFetch 或 SQLFetchScroll 时,驱动程序都会将当前行的数据传输到绑定到结果集列的变量中。如果结果集列和程序变量具有不同的数据类型,则驱动程序将处理数据转换。如果应用程序将 SQL_ATTR_ROW_ARRAY_SIZE 设置为大于 1,则它可以将结果列绑定到变量数组,这些变量数组将在每次调用 SQLFetchScroll 时被全部填充。
第二个选项基于 SQLGetData。应用程序不使用 SQLBindCol 将结果集列绑定到程序变量。在每次调用 SQLFetch 后,应用程序都为结果集中的每一列调用 SQLGetData 一次。SQLGetData 指示驱动程序将数据从某一特定的结果集列传输到特定的程序变量,并且指定该列和变量的数据类型。如果结果集列和程序变量具有不同的数据类型,则上述操作将允许驱动程序转换数据。Text、ntext 和 image 列通常太大,无法适合于程序变量中,但仍可以使用 SQLGetData 检索。如果结果列中的 text、ntext 或 image 数据大于程序变量,则 SQLGetData 将返回 SQL_SUCCESS_WITH_INFO 和 SQLSTATE 01004(字符串数据,右端被截断)。对 SQLGetData 的连续调用将返回 text 或 image 数据的连续块区。在到达数据末尾时,SQLGetData 将返回 SQL_SUCCESS。如果 SQL_ATTR_ROW_ARRAY_SIZE 大于 1,则每个提取都将返回一组行或行集。在使用 SQLGetData 前,必须首先使用 SQLSetPos 以指定该行集内的特定行作为当前行。
第三个选项是混用 SQLBindCol 和 SQLGetData。例如,应用程序可以绑定某一结果集的前十列,然后在每次提取时,都调用 SQLGetData 三次以便从三个未绑定的列中检索数据。在某一结果集包含一个或多个 text 或 image 列时,通常使用上述方法。
根据为结果集设置的游标选项,应用程序还可以使用 SQLFetchScroll 的滚动选项在结果集中滚动。
过多地使用 SQLBindCol 将某一结果集列绑定到程序变量将消耗较多系统资源,因为 SQLBindCol 将导致 ODBC 驱动程序分配内存。在您将某一结果列绑定到变量时,该绑定将在调用 SQLFreeHandle 释放语句句柄或调用 SQLFreeStmt(fOption 设置为 SQL_UNBIND)前保持有效。在该语句完成前绑定不自动撤消。
通过这一逻辑,您可以高效地处理使用不同参数多次执行同一 SELECT 语句的情况。因为结果集保持相同结构,所以,您可以将绑定该结果集一次,处理所有 SELECT 语句,然后在最后执行后调用 SQLFreeStmt(fOption 设置为 SQL_UNBIND)。在没有首先调用 SQLFreeStmt(fOption 设置为 SQL_UNBIND)以释放任何以前的绑定前,不应调用 SQLBindCol 以绑定结果集中的列。
在使用 SQLBindCol 时,您可以执行按行绑定或按列绑定。按行绑定比按列绑定稍快。
可以使用 SQLGetData 按列检索数据,而非使用 SQLBindCol 绑定结果集列。如果某一结果集只包含几行,则使用 SQLGetData 比使用 SQLBindCol 更快;否则,使用 SQLBindCol 可提供最佳性能。如果不是始终将数据放置于同一变量集中,则应使用 SQLGetData 来代替不断地重新绑定。只有在使用 SQLBindCol 绑定所有列后,才能对位于选择列表中的列使用 SQLGetData。该列还必须出现在已对其使用了 SQLGetData 的任何列之后。
用于将数据移入或移出程序变量的 ODBC 函数(例如 SQLGetData、SQLBindCol 和 SQLBindParameter)支持隐式数据类型转换。例如,如果应用程序将某一整数列绑定到某一字符串程序变量,则驱动程序将会首先自动把数据从整数转换为字符,然后将其置于该程序变量中。
应用程序中的数据转换应尽可能少。如果对应用程序执行的处理不要求数据转换,则应用程序应将列和参数绑定到同一数据类型的程序变量。但是,如果数据必须从一种类型转换为另一种类型,让驱动程序执行转换比在应用程序中执行转换的效率更高。SQL Server Native Client ODBC 驱动程序通常只将数据直接从网络缓冲区传输到应用程序的变量。请求驱动程序执行数据转换将强制驱动程序把数据存入缓冲区并使用 CPU 周期来转换数据。
程序变量应该足够大,以便存放从某一列中传输的数据,但 text、ntext 和 image 数据除外。如果某一应用程序尝试检索结果集数据,而放置这些数据的变量太小以致无法保存数据,则驱动程序将生成一个警告。这强制驱动程序为消息分配内存,并且驱动程序和应用程序都必须将 CPU 周期花在处理消息和执行错误处理上。应用程序应或者分配在大小上足以存放检索的数据的变量,或者在选择列表中使用 SUBSTRING 函数减小结果集中列的大小。
在使用 SQL_C_DEFAULT 指定 C 变量的类型时必须小心。SQL_C_DEFAULT 指定 C 变量的类型与列或参数的 SQL 数据类型匹配。如果为 ntext、nchar 或 nvarchar 列指定 SQL_C_DEFAULT,则 Unicode 数据将返回到应用程序。如果尚未对应用程序进行编码以处理 Unicode 数据,则上述操作可能导致不同的问题。对于 uniqueidentifier (SQL_GUID) 数据类型可能发生类型相同的问题。
text、ntext 和 image 数据通常太大,不适合单个程序变量,并且通常使用 SQLGetData 而非 SQLBindCol 进行处理。在使用服务器游标时,SQL Server Native Client ODBC 驱动程序将会优化,以便在提取行时不传输未绑定 text、ntext 或 image 列的数据。在应用程序为该列发出 SQLGetData 前,不会从服务器实际检索 text、ntext 或 image 数据。
这一优化可应用于应用程序,以便在用户在上下滚动游标时不显示 text、ntext 或 image 数据。在用户选择某一行后,应用程序可调用 SQLGetData 以检索 text、ntext 或 image 数据。这可以避免传输用户未选择的行的 text、ntext 或 image 数据,并可以避免传输非常大量的数据。