SQLBindCol 函数

一致性
引入的版本:ODBC 1.0 标准符合性:ISO 92

总结
SQLBindCol 将应用数据缓冲区绑定到结果集中的列。

Syntax

  
SQLRETURN SQLBindCol(  
      SQLHSTMT       StatementHandle,  
      SQLUSMALLINT   ColumnNumber,  
      SQLSMALLINT    TargetType,  
      SQLPOINTER     TargetValuePtr,  
      SQLLEN         BufferLength,  
      SQLLEN *       StrLen_or_IndPtr);  

Arguments

StatementHandle
[输入]语句句柄。

列号
[输入]结果集的列数要绑定。 列号按列序递增排列,从0开始,列0为书签列。 如果不使用书签——即SQL_ATTR_USE_BOOKMARKS语句属性设置为SQL_UB_OFF——则列号从1开始。

目标类型
[输入]*TargetValuePtr 缓冲区的C数据类型标识符。 当它用 SQLFetchSQLFetchScrollSQLBulkOperationsSQLSetPos 从数据源检索数据时,驱动会将数据转换成这种类型;当它通过 SQLBulkOperationsSQLSetPos 向数据源发送数据时,驱动程序会将该类型的数据转换。 有关有效C型数据类型和类型标识符的列表,请参见附录D:数据类型中的 C型别 部分。

如果 TargetType 参数是区间数据类型,则数据使用默认的区间前导精度(2)和默认区间秒精度(6),分别在 ARD 的SQL_DESC_DATETIME_INTERVAL_PRECISION和SQL_DESC_PRECISION字段中设置。 如果 TargetType 参数被SQL_C_NUMERIC,则使用默认精度(驱动程序定义)和默认刻度(0),这些参数在 ARD 的 SQL_DESC_PRECISION 和 SQL_DESC_SCALE 字段中设置。 如果任何默认精度或缩放不合适,应用程序应通过调用 SQLSetDescFieldSQLSetDescRec 显式设置相应的描述符字段。

还可以指定扩展的 C 数据类型。 有关详细信息,请参阅 ODBC 中的 C 数据类型

目标值Ptr
[延迟输入/输出]指向数据缓冲区绑定到列。 SQLFetchSQLFetchScroll 返回该缓冲区中的数据。 当操作SQL_FETCH_BY_BOOKMARK时,SQLBulkOperations 返回该缓冲区中的数据;当操作被SQL_ADD或SQL_UPDATE_BY_BOOKMARK时,它会从该缓冲区获取数据。 当操作SQL_REFRESH时,SQLSetPos 返回该缓冲区中的数据;当操作SQL_UPDATE时,它会从该缓冲区获取数据。

如果 TargetValuePtr 是空指针,驱动程序解绑该列的数据缓冲区。 应用程序可以通过调用带有SQL_UNBIND选项的 SQLFreeStmt 来解绑所有列。 应用程序可以解绑某列的数据缓冲区,但该列仍绑定长度/指示符缓冲区,前提是调用 SQLBindColTargetValuePtr 参数是空指针,但 StrLen_or_IndPtr 参数是有效值。

BufferLength
[输入]*TargetValuePtr 缓冲区的长度(字节单位)。

驱动程序使用 BufferLength 以避免在返回可变长度数据(如字符或二进制数据)时写入超过*TargetValuePtr 缓冲区的末尾。 注意,驱动程序在返回字符数据到 *TargetValuePtr 时,计数了空终止字符。 *因此,TargetValuePtr必须包含空终止字符的空间,否则驱动会截断数据。

当驱动程序返回固定长度的数据,如整数或日期结构时,忽略 缓冲区 长度,并假设缓冲区足够大以容纳数据。 因此,应用程序必须为固定长度数据分配足够大的缓冲区,否则驱动程序会写入缓冲区末端之后。

BufferLength 小于 0 时,SQLBindCol 返回 SQLSTATE HY090(字符串或缓冲区长度无效),但当 BufferLength 为 0 时则不返回。 然而,如果 TargetType 指定了字符类型,应用程序不应将 BufferLength 设为 0,因为符合 ISO CLI 标准的驱动程序在此情况下返回 SQLSTATE HY090(无效字符串或缓冲区长度)。

StrLen_or_IndPtr
[延迟输入/输出]指向长度/指示缓冲区,绑定到列。 SQLFetchSQLFetchScroll 会在这个缓冲区返回一个值。 当操作为SQL_ADD、SQL_UPDATE_BY_BOOKMARK或SQL_DELETE_BY_BOOKMARK时,SQLBulkOperations 会从该缓冲区获取一个值。 当操作SQL_FETCH_BY_BOOKMARK时,SQLBulkOperations 会返回该缓冲区中的一个值。 当操作SQL_REFRESH时,SQLSetPos 会返回该缓冲区中的一个值;当操作被SQL_UPDATE时,它会从该缓冲区获取一个值。

SQLFetchSQLFetchScrollSQLBulkOperationsSQLSetPos 可以在长度/指示缓冲区返回以下值:

  • 可返回的数据长度

  • SQL_NO_TOTAL

  • SQL_NULL_DATA

应用程序可以在长度/指示缓冲区中输入以下值,用于 SQLBulkOperationsSQLSetPos

  • 发送数据的长度

  • SQL_NTS

  • SQL_NULL_DATA

  • SQL_DATA_AT_EXEC

  • SQL_LEN_DATA_AT_EXEC宏的结果

  • SQL_COLUMN_IGNORE

如果指示缓冲区和长度缓冲区是独立缓冲区,指示缓冲区只能返回SQL_NULL_DATA,而长度缓冲区可以返回所有其他值。

更多信息请参见 SQLBulkOperations 函数SQLFetch 函数SQLSetPos 函数以及 使用 长度/指示值

如果 StrLen_or_IndPtr 是空指针,则不使用长度或指示值。 这是在获取数据时出现的错误,且数据为NULL。

如果应用程序将在 64 位操作系统上运行,请参阅 ODBC 64 位信息

Returns

SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、SQL_ERROR 或SQL_INVALID_HANDLE。

诊断

SQLBindCol 返回 SQL_ERROR 或 SQL_SUCCESS_WITH_INFO 时,可以通过调用 SQLGetDiagRec 获得关联的 SQLSTATE 值,Handle 为 SQL_HANDLE_STMT,Handle 为 StatementHandle 下表列出了 SQLBindCol 通常返回的SQLSTATE值,并在此函数的上下文中解释了每个值;“(DM)” 符号位于驱动程序管理器返回的 SQLSTATE 描述之前。 除非另有说明,否则与每个 SQLSTATE 值关联的返回代码SQL_ERROR。

SQLSTATE Error Description
01000 常规警告 特定于驱动程序的信息性消息。 (函数返回SQL_SUCCESS_WITH_INFO。)
07006 受限数据类型属性冲突 (DM) ColumnNumber 参数为 0,TargetType 参数也没有 SQL_C_BOOKMARK 或 SQL_C_VARBOOKMARK。
07009 无效描述子索引 参数 ColumnNumber 的值超过了结果集中列数的最大值。
HY000 常规错误 发生错误:没有特定的 SQLSTATE,也没有定义特定于实现的 SQLSTATE。 *MessageText 缓冲区中 SQLGetDiagRec 返回的错误消息描述错误及其原因。
HY001 内存分配错误 驱动程序无法分配支持执行或完成函数所需的内存。
HY003 应用程序缓冲区类型无效 参数 TargetType 既不是有效的数据类型,也不是SQL_C_DEFAULT。
HY010 函数序列错误 (DM) 为与 StatementHandle 关联的连接句柄调用异步执行函数。 当调用 SQLBindCol 时,这个异步函数仍在执行。

(DM) 为 StatementHandle 调用了 SQLExecuteSQLExecDirectSQLMoreResults,并返回了SQL_PARAM_DATA_AVAILABLE。 在检索所有流式处理参数的数据之前调用此函数。

(DM) 为 StatementHandle 调用异步执行函数,并在调用此函数时仍在执行。

(DM) 为 StatementHandle 调用了 SQLExecuteSQLExecDirectSQLBulkOperationsSQLSetPos,并返回了SQL_NEED_DATA。 在为所有数据执行参数或列发送数据之前调用此函数。
HY013 内存管理错误 无法处理函数调用,因为基础内存对象无法访问,可能是因为内存条件低。
HY090 字符串或缓冲区长度无效 (DM) 参数 BufferLength 指定的值小于 0。

(DM)司机是ODBC 2型。x 驱动程序中, ColumnNumber 参数设置为 0,参数 BufferLength 指定的值不等于 4。
HY117 连接因未知事务状态而挂起。 仅允许断开连接和只读函数。 (DM) 有关挂起状态的详细信息,请参阅 SQLEndTran 函数
HYC00 未实现可选功能 驱动程序或数据源不支持由 TargetType 参数与对应列驱动特定 SQL 类型组合所指定的转换。

参数 ColumnNumber 为 0,且驱动不支持书签。

该驱动程序仅支持 ODBC 2。x 和参数 TargetType 是以下之一:

SQL_C_NUMERIC SQL_C_SBIGINT SQL_C_UBIGINT

以及附录D中C数据 类型 中列出的任何区间C数据类型。

该驱动程序仅支持 3.50 之前的 ODBC 版本,参数 TargetType 被SQL_C_GUID。
HYT01 超过连接超时时间 在数据源响应请求之前,连接超时期限已过期。 连接超时期限通过 SQLSetConnectAttr 设置,SQL_ATTR_CONNECTION_TIMEOUT。
IM001 驱动程序不支持此函数 (DM) 与 StatementHandle 关联的驱动程序不支持该函数。

Comments

SQLBindCol 用于将结果集中的列关联或 绑定 到应用程序中的数据缓冲区和长度/指示缓冲区。 当应用程序调用 SQLFetchSQLFetchScrollSQLSetPos 获取数据时,驱动程序返回指定缓冲区中绑定列的数据;更多信息请参见 SQLFetch 函数。 当应用程序调用 SQLBulkOperations 更新或插入行或 SQLSetPos 更新行时,驱动程序会从指定的缓冲区获取绑定列的数据;更多信息请参见 SQLBulkOperations 函数SQLSetPos 函数。 有关绑定的更多信息,请参见检索 结果(基础)

注意,列不必绑定即可检索数据。 应用程序还可以调用 SQLGetData 从列中获取数据。 虽然可以绑定行中的某些列并调用其他列的 SQLGetData ,但这会受到一些限制。 更多信息请参见 SQLGetData

装订、解订和重新装订列

列可以随时被绑定、解绑定或重新绑定,即使数据已经从结果集中取出。 新的绑定将在下一次调用使用绑定的函数时生效。 例如,假设一个应用程序绑定结果集中的列并调用 SQLFetch。 驱动程序返回绑定缓冲区中的数据。 现在假设应用程序将列绑定到另一组缓冲区。 驱动程序不会将刚取出的行数据放入新绑定的缓冲区。 相反,它会等到再次调用 SQLFetch 后,将下一行的数据放入新绑定的缓冲区。

注释

在将列绑定到列0之前,语句属性SQL_ATTR_USE_BOOKMARKS应始终设置。 这不是必须的,但强烈建议。

绑定列

绑定列时,应用程序调用 SQLBindCol ,传递数据缓冲区的列号、类型、地址和长度,以及长度/指示缓冲区的地址。 有关这些地址的使用方式,请参见本节后面的“缓冲区地址”。 有关绑定列的更多信息,请参见 使用 SQLBindCol

这些缓冲区的使用被推迟;也就是说,应用程序在 SQLBindCol 中绑定它们,但驱动程序通过其他函数访问它们——即 SQLBulkOperationsSQLFetch、SQLFetchScrollSQLSetPos。 应用程序有责任确保只要绑定有效, SQLBindCol 中指定的指针始终有效。 如果应用程序允许这些指针失效——例如释放缓冲区——然后调用一个期望它们有效的函数,后果则未定义。 更多信息请参见 延期缓冲区

该绑定一直有效,直到被新的绑定取代、列被解除绑定,或语句被释放。

解订柱

要解绑单一列,应用程序调用 SQLBindCol,ColumnNumber 设置为该列号,TargetValuePtr 设置为空指针。 如果 ColumnNumber 指的是未绑定的列, SQLBindCol 仍然返回SQL_SUCCESS。

要解绑所有列,应用程序调用 SQLFreeStmt,fOption 设为 SQL_UNBIND。 这也可以通过将ARD的场SQL_DESC_COUNT设为零来实现。

重新装订柱

应用程序可以执行两个操作之一来更改绑定:

  • 调用 SQLBindCol 为已经绑定的列指定新的绑定。 驱动程序使用新绑定覆盖旧绑定。

  • 指定一个偏移量添加到由绑定调用 SQLBindCol 指定的缓冲区地址上。 更多信息请参见下一节“装订偏移”。

绑定偏移量

绑定偏移量是在数据和长度/指示缓冲区的地址(如 TargetValuePtrStrLen_or_IndPtr 参数中指定)被添加的值,然后才被取消引用。 当使用偏移时,绑定是应用程序缓冲区布局的“模板”,应用程序可以通过改变偏移量将该“模板”移动到内存的不同区域。 由于每个绑定中每个地址都添加了相同的偏移量,不同列缓冲区之间的相对偏移必须在每个缓冲区组内保持一致。 当采用行数装订时,这一点总是成立;应用必须仔细布局缓冲区,才能在使用列级绑定时实现这一点。

使用绑定偏移量的效果基本上和调用 SQLBindCol重新绑定列一样。 区别在于,调用 SQLBindCol 会指定数据缓冲区和长度/指示缓冲区的新地址,而使用绑定偏移量不会改变地址,只是增加一个偏移量。 应用程序可以随时指定新的偏移量,且该偏移量总是添加到最初绑定的地址上。 特别地,如果偏移量设置为0或语句属性设置为空指针,驱动程序使用最初绑定的地址。

为了指定绑定偏移量,应用程序将SQL_ATTR_ROW_BIND_OFFSET_PTR语句属性设置为SQLINTEGER 缓冲区的地址。 在应用程序调用使用绑定的函数之前,会在缓冲区中放入一个以字节为单位的偏移量。 为了确定缓冲区的地址,驱动程序将偏移量加到绑定中的地址上。 地址和偏移量的和必须是有效地址,但偏移量添加的地址不必有效。 关于绑定偏移的使用方式,请参见本节后面的“缓冲区地址”。

绑定数组

如果行集大小(SQL_ATTR_ROW_ARRAY_SIZE语句属性的值)大于1,应用程序绑定的是缓冲区数组而非单个缓冲区。 更多信息请参见 “阻挡光标”。

应用程序可以通过两种方式绑定数组:

  • 将数组绑定到每个列。 这被称为 列绑定 ,因为每个数据结构(数组)都包含单个列的数据。

  • 定义一个结构来存储整行的数据,并绑定这些结构的数组。 这被称为 逐行绑定 ,因为每个数据结构都包含单一行的数据。

每个缓冲区数组的元素数量必须至少等于行集的大小。

注释

应用程序必须验证对齐的有效性。 有关阵营考虑的更多信息,请参见 阵营

按列绑定

在逐列绑定中,应用程序为每一列绑定独立的数据数组和长度/指示符数组。

要使用列绑定,应用程序首先将SQL_ATTR_ROW_BIND_TYPE语句属性设置为SQL_BIND_BY_COLUMN。 (这是默认值。对于要绑定的每个列,应用程序将执行以下步骤:

  1. 分配一个数据缓冲数组。

  2. 分配长度/指示器缓冲区数组。

    注释

    如果使用列式绑定时,应用程序直接写入描述符,则可以将单独的数组用于长度和指示器数据。

  3. 调用 SQLBindCol 并使用以下参数:

    • TargetType 是数据缓冲数组中单个元素的类型。

    • TargetValuePtr 是数据缓冲数组的地址。

    • 缓冲长度 是数据缓冲数组中单个元素的大小。 当数据是固定长度的数据时,将忽略 BufferLength 参数。

    • StrLen_or_IndPtr 是长度/指示器数组的地址。

有关该信息如何使用的更多信息,请参见本节后面的“缓冲区地址”。 关于按列装订的更多信息,请参见 BindingColumn-Wise

按行绑定

在按行绑定中,应用程序定义一个结构,包含每个待绑定列的数据缓冲区和长度/指示符缓冲区。

若要使用按行绑定,应用程序将执行以下步骤:

  1. 定义一个结构以存储单行数据(包括数据和长度/指示缓冲区),并分配这些结构的数组。

    注释

    如果使用行绑定时应用程序直接写入描述符,则可以将单独的字段用于长度和指示器数据。

  2. 将SQL_ATTR_ROW_BIND_TYPE语句属性设置为包含单行数据的结构大小,或将结果列绑定到缓冲区实例的大小。 长度必须包含所有绑定列的空间,以及结构或缓冲区的任何填充,以确保当绑定列的地址按指定长度递增时,结果会指向下一行同一列的起点。 在 ANSI C 中使用 sizeof 运算符时,可以保证此行为。

  3. 调用 SQLBindCol ,每个列的绑定参数如下:

    • TargetType 是要绑定到该列的数据缓冲区成员类型。

    • TargetValuePtr 是第一个数组元素中数据缓冲区成员的地址。

    • 缓冲长度 是数据缓冲区成员的大小。

    • StrLen_or_IndPtr 是要绑定的长度/指示器成员的地址。

有关该信息如何使用的更多信息,请参见本节后面的“缓冲区地址”。 关于按列装订的更多信息,请参见 BindingRow-Wise

缓冲区地址

缓冲区地址是数据或长度/指示缓冲区的实际地址。 驱动程序在写入缓冲区之前(例如取指时)计算缓冲区地址。 它由以下公式计算,该公式使用了 TargetValuePtrStrLen_or_IndPtr 参数中指定的地址、绑定偏移量和行号:

绑定地址 + 绑定偏移 量 + ((行号 - 1) x 元素大小

其中公式的变量定义如下表所述。

Variable Description
绑定地址 对于数据缓冲区,地址是 SQLBindCol 中用 TargetValuePtr 参数指定的。

对于长度/指示缓冲区,地址是 SQLBindCol 中用 StrLen_or_IndPtr 参数指定的。 更多信息请参见“描述符和 SQLBindCol” 部分的“附加注释”。

如果绑定地址为0,则不会返回任何数据值,即使前述公式计算的地址非零。
绑定偏移 如果使用行绑定,则存储在带有SQL_ATTR_ROW_BIND_OFFSET_PTR语句属性的地址上的值。

如果使用列绑定,或者SQL_ATTR_ROW_BIND_OFFSET_PTR语句属性的值是空指针,绑 定偏移 量为0。
行号 行集中行的基于1的数字。 对于默认的单行取用,这个数值为1。
元素大小 绑定数组中元素的大小。

如果使用列绑定,长度/指示符缓冲区的大小( SQLINTEGER) 为单位。 对于数据缓冲区,如果数据类型是可变长度,则为 SQLBindColBufferLength 参数的值;如果数据类型是固定长度,则为数据类型的大小。

如果采用行绑定,则该值为数据和长度/指示缓冲区的SQL_ATTR_ROW_BIND_TYPE语句属性值。

描述符与 SQLBindCol

以下章节将描述 SQLBindCol 如何与描述符交互。

Caution

调用 SQLBindCol 对一个语句可能影响其他语句。 当显式分配与该语句关联的 ARD 并且也与其他语句关联时,将发生这种情况。 由于 SQLBindCol 修改描述符,修改适用于所有关联该描述符的语句。 如果这不是要求的行为,应用程序应在调用 SQLBindCol 前将该描述符与其他语句分离。

参数映射

从概念上讲, SQLBindCol 依次执行以下步骤:

  1. 调用 SQLGetStmtAttr 以获取 ARD 句柄。

  2. 调用 SQLGetDescField 获取该描述符的SQL_DESC_COUNT字段,如果 ColumnNumber 参数中的值超过 SQL_DESC_COUNT,则调用 SQLSetDescField 将 SQL_DESC_COUNT 的值提高到 ColumnNumber

  3. 多次调用 SQLSetDescField ,为ARD的以下字段分配值:

    • 将 SQL_DESC_TYPE 和 SQL_DESC_CONCISE_TYPE 设置为 TargetType 的值,但如果 TargetType 是日期时间或区间子类型的简明标识符之一,则分别将 SQL_DESC_TYPE 设置为 SQL_DATETIME 或 SQL_INTERVAL;将SQL_DESC_CONCISE_TYPE设置为简明标识符;并将SQL_DESC_DATETIME_INTERVAL_CODE设置为对应的日期时间或区间子码。

    • 根据 TargetType 设置 SQL_DESC_LENGTH、SQL_DESC_PRECISION、SQL_DESC_SCALE 和 SQL_DESC_DATETIME_INTERVAL_PRECISION 中的一个或多个。

    • 将SQL_DESC_OCTET_LENGTH字段设置为 BufferLength 的值

    • 将SQL_DESC_DATA_PTR字段设置为 TargetValuePtr

    • 将SQL_DESC_INDICATOR_PTR场设为 StrLen_or_IndPtr值。 (详见下一段。)

    • 将SQL_DESC_OCTET_LENGTH_PTR字段设置为 StrLen_or_IndPtr。 (详见下一段。)

StrLen_or_IndPtr参数所指变量既用于指示信息,也用于长度信息。 如果取指在该列遇到空值,它会将SQL_NULL_DATA存储在这个变量中;否则,它会将数据长度存储在这个变量中。 将空指针传递为 StrLen_or_IndPtr 可以防止取指针返回数据长度,但如果遇到空值且无法返回SQL_NULL_DATA,取指针会失败。

如果调用 SQLBindCol 失败,ARD 中本应设置的描述符字段内容未定义,ARD SQL_DESC_COUNT字段的值保持不变。

COUNT字段的隐式重置

SQLBindCol 只有在 ColumnNumber 参数会增加 SQL_DESC_COUNT 值时,才将 SQL_DESC_COUNT 设置为 ColumnNumber 参数的值。 如果 TargetValuePtr 参数中的值是空指针,且 ColumnNumber 参数中的值等于 SQL_DESC_COUNT(即解绑最大束缚列时),则 SQL_DESC_COUNT 设置为剩余最大束缚列的编号。

关于SQL_DEFAULT的注意事项

为了成功检索列数据,应用程序必须正确确定应用缓冲区中数据的长度和起始点。 当应用程序指定显式 目标类型时,应用误解很容易被发现。 然而,当应用程序指定SQL_DEFAULT的 目标类型 时, SQLBindCol 可以应用于与应用程序预期数据类型的不同列,无论是通过元数据的更改,还是将代码应用到不同的列。 在这种情况下,应用程序可能并不总是确定被取列数据的起始或长度。 这可能导致未报告的数据错误或内存违规。

代码示例

在以下示例中,应用程序在客户表上执行 SELECT 语句,返回按姓名排序的客户ID、姓名和电话号码的结果集。 然后调用 SQLBindCol 将数据列绑定到本地缓冲区。 最后,应用程序用 SQLFetch 获取每行数据,并打印每位客户的姓名、ID 和电话号码。

更多代码示例请参见 SQLBulkOperations 函数SQLColumns 函数SQLFetchScroll 函数SQLSetPos 函数

// SQLBindCol_ref.cpp  
// compile with: odbc32.lib  
#include <windows.h>  
#include <stdio.h>  
  
#define UNICODE  
#include <sqlext.h>  
  
#define NAME_LEN 50  
#define PHONE_LEN 60
  
void show_error() {  
   printf("error\n");  
}  
  
int main() {  
   SQLHENV henv;  
   SQLHDBC hdbc;  
   SQLHSTMT hstmt = 0;  
   SQLRETURN retcode;  
   SQLWCHAR szName[NAME_LEN], szPhone[PHONE_LEN], sCustID[NAME_LEN];  
   SQLLEN cbName = 0, cbCustID = 0, cbPhone = 0;  
  
   // Allocate environment handle  
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
  
   // Set the ODBC version environment attribute  
   if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
      retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);   
  
      // Allocate connection handle  
      if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
         retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);  
  
         // Set login timeout to 5 seconds  
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
            SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  
            // Connect to data source  
            retcode = SQLConnect(hdbc, (SQLWCHAR*) L"NorthWind", SQL_NTS, (SQLWCHAR*) NULL, 0, NULL, 0);  
  
            // Allocate statement handle  
            if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {   
               retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);   
  
               retcode = SQLExecDirect(hstmt, (SQLWCHAR *) L"SELECT CustomerID, ContactName, Phone FROM CUSTOMERS ORDER BY 2, 1, 3", SQL_NTS);  
               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
  
                  // Bind columns 1, 2, and 3  
                  retcode = SQLBindCol(hstmt, 1, SQL_C_WCHAR, &sCustID, 100, &cbCustID);  
                  retcode = SQLBindCol(hstmt, 2, SQL_C_WCHAR, szName, NAME_LEN, &cbName);  
                  retcode = SQLBindCol(hstmt, 3, SQL_C_WCHAR, szPhone, PHONE_LEN, &cbPhone);   
  
                  // Fetch and print each row of data. On an error, display a message and exit.  
                  for (int i=0 ; ; i++) {  
                     retcode = SQLFetch(hstmt);  
                     if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)  
                        show_error();  
                     if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)  
                     {
                        //replace wprintf with printf
                        //%S with %ls
                        //warning C4477: 'wprintf' : format string '%S' requires an argument of type 'char *'
                        //but variadic argument 2 has type 'SQLWCHAR *'
                        //wprintf(L"%d: %S %S %S\n", i + 1, sCustID, szName, szPhone);  
                        printf("%d: %ls %ls %ls\n", i + 1, sCustID, szName, szPhone);  
                    }    
                     else  
                        break;  
                  }  
               }  
  
               // Process data  
               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {  
                  SQLCancel(hstmt);  
                  SQLFreeHandle(SQL_HANDLE_STMT, hstmt);  
               }  
  
               SQLDisconnect(hdbc);  
            }  
  
            SQLFreeHandle(SQL_HANDLE_DBC, hdbc);  
         }  
      }  
      SQLFreeHandle(SQL_HANDLE_ENV, henv);  
   }  
}  

另见 ODBC项目示例

有关以下内容的信息 请参阅
返回有关结果集中的列的信息 SQLDescribeCol函数
提取数据块或滚动结果集 SQLFetchScroll 函数
提取多行数据 SQLFetch 函数
在语句上释放列缓冲区 SQLFreeStmt 函数
提取部分或全部数据列 SQLGetData 函数
返回结果集列数 SQLNumResultCols 函数