Mysql使用SQLFetch()获取结果数据 - 基于 SQLGetData

本文介绍了如何使用SQLFetch和SQLGetData函数从数据库结果集中获取数据,包括基于SQLBindCol、单独使用SQLGetData以及两者结合的方法。通过示例代码展示了如何处理不同列的数据,并解释了SQLGetData函数的参数详细说明,强调了BufferLength的重要性以及处理变长数据时的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SQLFetch() 函数获取结果数据有三种方式:

1. 基于SQLBindCol 函数

2. 基于SQLGetData 函数

3. SQLBindCol 和 SQLGetData 函数结合。

基于SQLBindCol 函数的方法参见: Mysql使用SQLFetch()获取结果数据 - 基于 SQLBindCol

目录

1. 参数简介

2. 代码示例:

2.1 示例

2.2 结果:

3. 其他C类型名称(不全,详情查看sqlext.h): 

4. SQLBindCol 函数参数详细说明,摘自MSDN。

1. 函数及参数简介

        应用程序不使用SQLBindCol将结果集列绑定到程序变量。每次调用SQLFetch之后,应用程序都会为结果集中的每一列调用SQLGetData一次。SQLGetData指示驱动程序将数据从特定的结果集列转移到特定的程序变量,并指定列和变量的数据类型。这允许驱动程序在结果列和程序变量具有不同的数据类型时转换数据。Text、ntext和image列通常太大,无法放入程序变量,但仍然可以使用SQLGetData检索。如果结果列中的文本、ntext或图像数据大于程序变量,SQLGetData将返回SQL_SUCCESS_WITH_INFO和SQLSTATE 01004(右截短的字符串数据)。对SQLGetData的连续调用将返回连续的文本或图像数据块。

        简单来说使用 SQLGetData 时,每调用一次 SQLFetch函数获取的结果集,就调用 SQLGetData 获取指定列的值。

SQLRETURN SQLGetData(
     SQLHSTMT     StatementHandle,             // [Input]
     SQLUSMALLINT     ColumnNumber,            // [Input]
     SQLSMALLINT     TargetType,               // [Input]
     SQLPOINTER     TargetValuePtr,            // [Output]
          SQLLEN     BufferLength,             // [Input]
          SQLLEN *     StrLen_or_IndPtr        // [Output]
); 

简单的来说:

参数1:操作的句柄。

参数2:要进行操作的列号,从1开始

参数3:该列的数据类型

参数4:存储该列的结果值变量

参数5:指定结果数据的大小

参数6:返回获取的结果的大小

具体参数释义见文末,摘自MSDN。

2. 代码示例:

2.1 示例

SQLCHAR t1[32], t2[255], t3[255];
SQLLEN Strlen_or_IndPtr = 0;    
for (int i = 0;; i++)
    {
        res = SQLFetch(myStatementHandle);     //获取结果集
        res = SQLGetData(myStatementHandle, 1, SQL_C_DEFAULT, &t1, 32, &Strlen_or_IndPtr);       //  获取结果集中列数据
        res = SQLGetData(myStatementHandle, 2, SQL_C_DEFAULT, &t2, 255, &Strlen_or_IndPtr);
        res = SQLGetData(myStatementHandle, 3, SQL_C_DEFAULT, &t3, 255, &Strlen_or_IndPtr);
        
        if (res == SQL_ERROR || res == SQL_SUCCESS_WITH_INFO)
            break;
        if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO)
        {
            cout << i + 1 << " -- " << t1 <<" -- " << t2 << " -- " << t3 << " -- " << Strlen_or_IndPtr << endl;
        }
        else
        {
            cout << res;
            break;
        }
    }

【释】:

t1[32], t2[255], t3[255] 变量和数据表的列对应。如下图:

数据表

 注意:定义变量的时候一定要指定变量类型,不然以SQLPOINTER     定义变量时,结果为ASCII码,见下面的结果图2。

res = SQLGetData(myStatementHandle, 1, SQL_C_DEFAULT, &t1, 32, &Strlen_or_IndPtr);

 myStatementHandle:为句柄;

1:代表第 1 列;

SQL_C_DEFAULT:指定结果的数据类型,根据数据表中的定义来决定,其他C类型名称见文末;SQL_C_DEFAULT 是根据数据源类型来决定变量类型

t1:保存结果变量;

32:指定结果的大小,注意要留出终止字符的空间;

Strlen_or_IndPtr:返回结果数据的大小。

2.2 结果:

结果图 1

 如果存储结果的指针定义成  SQLPOINTER  类型,则结果为ASCII值,见下图2。

结果图 2

3. 其他C类型名称 

(不全,详情查看sqlext.h)
#define SQL_C_CHAR    SQL_CHAR                 /* CHAR, VARCHAR, DECIMAL, NUMERIC */
#define SQL_C_LONG    SQL_INTEGER           /* INTEGER                      */
#define SQL_C_SHORT   SQL_SMALLINT        /* SMALLINT                     */
#define SQL_C_FLOAT   SQL_REAL                 /* REAL                         */
#define SQL_C_DOUBLE  SQL_DOUBLE         /* FLOAT, DOUBLE                */

4. SQLGetData 函数参数详细说明

摘自MSDN。

(1)StatementHandle

[Input] Statement handle.
【释义】 语句句柄。

(2)ColumnNumber

[Input] Number of the column for which to return data. Result set columns are numbered in increasing column order starting at 1. The bookmark column is column number 0; this can be specified only if bookmarks are enabled.
【释义】
要为其返回数据的列的编号。结果集列从1开始按列顺序递增编号。书签列为列号0;只有启用了书签,才能指定此参数。

(3)TargetType

[Input] The type identifier of the C data type of the * TargetValuePtr buffer. For a list of valid C data types and type identifiers, see the C Data Types section in Appendix D: Data Types. If TargetType is SQL_ARD_TYPE, the driver uses the type identifier specified in the SQL_DESC_CONCISE_TYPE field of the ARD. If it is SQL_C_DEFAULT, the driver selects the default C data type based on the SQL data type of the source.
【释义】
*TargetValuePtr缓冲区的C数据类型的类型标识符。有关有效的C数据类型和类型标识符的列表,请参见附录D:数据类型中的C数据类型部分。如果TargetType为SQL_ARD_TYPE,驱动使用ARD的SQL_DESC_CONCISE_TYPE字段中指定的类型标识符。如果是SQL_C_DEFAULT,驱动程序将根据源的SQL数据类型选择默认的C数据类型。

(4)TargetValuePtr

[Output] Pointer to the buffer in which to return the data.
【释义】
指向在其中返回数据的缓冲区的指针

(5)BufferLength

[Input] Length of the * TargetValuePtr buffer in bytes.
The driver uses BufferLength to avoid writing past the end of the * TargetValuePtr buffer when returning variable-length data, such as character or binary data. Note that the driver counts the null-termination character when returning character data to * TargetValuePtr. * TargetValuePtr must therefore contain space for the null-termination character, or the driver will truncate the data.
When the driver returns fixed-length data, such as an integer or a date structure, the driver ignores BufferLength and assumes the buffer is large enough to hold the data. It is therefore important for the application to allocate a large enough buffer for fixed-length data or the driver will write past the end of the buffer.
SQLGetData returns SQLSTATE HY090 (Invalid string or buffer length) when BufferLength is less than 0 but not when BufferLength is 0.
【释义】
驱动程序使用BufferLength来避免在返回变长数据(如字符或二进制数据)时写入超过*TargetValuePtr缓冲区的末尾。注意,当返回字符数据到*TargetValuePtr时,驱动程序计数空终止字符。因此TargetValuePtr必须包含空终止字符的空间,否则驱动程序将截断数据。
当驱动程序返回固定长度的数据时,例如一个整数或一个日期结构,驱动程序忽略BufferLength并假设缓冲区足够大以容纳数据。因此,对于应用程序来说,为固定长度的数据分配一个足够大的缓冲区是很重要的,否则驱动程序将写入超过缓冲区末端的数据。
当BufferLength小于0时返回SQLSTATE HY090(无效字符串或缓冲区长度),而当BufferLength为0时则不返回SQLSTATE HY090。

(6)StrLen_or_IndPtr

[Output] Pointer to the buffer in which to return the length or indicator value. If this is a null pointer, no length or indicator value is returned. This returns an error when the data being fetched is NULL.
【释义】
指向缓冲区的指针,在其中返回长度或指示值。如果这是一个空指针,则不返回长度或指示值。当获取的数据为NULL时,将返回一个错误
SQLGetData can return the following values in the length/indicator buffer:
  • The length of the data available to return
  • SQL_NO_TOTAL
  • SQL_NULL_DATA
For more information, see Using Length/Indicator Values and "Comments" in this topic.
<think>好的,用户现在问的是如何在C++获取SQL Server的数据并保存到字符串里。之前他们问过如何获取两个数据库表中重复的列数据,现在的问题可能是在同一个项目中的进一步需求,比如需要将查询结果处理后存储起来。 首先,我需要确定用户的使用场景。他们可能是在开发一个需要从SQL Server读取数据并进行处理的应用程序,比如生成报告、数据转换或者展示。保存到字符串可能是为了后续处理,比如输出到日志、序列化或者传输到其他系统。 接下来要考虑用户的需求。用户可能对C++操作SQL Server的流程不太熟悉,特别是如何连接数据库、执行查询以及处理结果集。他们可能需要一个具体的示例代码,同时希望了解每个步骤的细节和注意事项,确保代码能够正确运行。 用户可能没有明确提到的深层需求包括错误处理、资源管理和性能优化。比如,在连接数据库时如何处理异常,如何防止内存泄漏,以及如何高效地处理大量数据。这些都是实际开发中常见的问题,需要一并考虑进去。 我需要选择合适的库来连接SQL Server。之前他们用的是MySQL Connector/C++,但这次是SQL Server,所以应该推荐ODBC或者Microsoft的官方库,比如Microsoft ODBC Driver for SQL Server或者Microsoft的OLE DB。ODBC是比较通用的选择,兼容性更好,所以示例代码中使用ODBC会比较合适。 然后,编写示例代码的步骤包括:连接数据库,执行查询,遍历结果集,将每一列数据转换为字符串,并保存起来。需要注意ODBC API的使用方法,比如分配句柄、连接字符串、执行SQL语句、绑定列内存等。此外,错误处理非常重要,每个ODBC函数调用后都应该检查返回码,确保操作成功。 用户可能对ODBC不太熟悉,所以需要详细解释每个步骤的作用,比如SQLAllocHandle、SQLDriverConnect、SQLExecDirect等函数的功能。同时,处理结果集时,如何获取每一行的数据,并将不同数据类型转换为字符串也是关键点。 另外,数据类型转换部分需要特别说明,比如如何处理整数、浮点数、日期时间等不同类型的数据,确保转换后的字符串格式正确。用户可能需要根据实际情况调整转换逻辑,特别是日期时间和二进制数据,可能需要特定的格式处理。 资源释放部分也是重点,比如释放句柄、断开连接,避免内存泄漏。需要提醒用户在代码中正确释放所有分配的资源,即使在发生异常的情况下也要确保资源被释放,可能需要使用try-catch块或者在析构函数中处理。 最后,注意事项部分需要涵盖连接字符串的格式、Unicode与ANSI字符的处理、大数据量的分页查询以及错误处理的细节。这些都能帮助用户在实际应用中避免常见的问题,提升代码的健壮性和效率。 总结来说,用户需要一个完整的示例,详细解释如何使用ODBC在C++中连接SQL Server,执行查询,并将结果保存到字符串中,同时需要覆盖错误处理、资源管理和数据类型转换等关键点,确保代码的可靠性和实用性。</think>在 C++ 中从 SQL Server 获取数据并保存到字符串中,通常需要以下步骤: **使用 ODBC(Open Database Connectivity)或 Microsoft 的 SQL Server 专用库(如 `Microsoft Data Access Components, MDAC`)**。以下是一个基于 ODBC 的详细实现方法: --- ### **核心步骤** 1. **配置 ODBC 数据源** 确保 SQL Server 的 ODBC 驱动已安装,并在系统数据源中配置连接(可选,也可直接通过连接字符串连接)。 2. **连接数据库** 使用 `sql.h` 和 `sqlext.h` 头文件中的 ODBC API 建立连接。 3. **执行 SQL 查询** 发送 SQL 语句(如 `SELECT`)到数据库。 4. **获取结果集并保存到字符串** 遍历结果集,逐行读取数据并转换为字符串。 --- ### **示例代码(使用 ODBC)** ```cpp #include <windows.h> #include <sql.h> #include <sqlext.h> #include <iostream> #include <string> #include <vector> // 错误处理函数 void checkODBCError(SQLHANDLE handle, SQLSMALLINT type, RETCODE retcode) { if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) return; SQLCHAR sqlstate[1024]; SQLCHAR message[1024]; SQLSMALLINT i = 1; SQLSMALLINT len; SQLRETURN rc; while ((rc = SQLGetDiagRec(type, handle, i, sqlstate, NULL, message, sizeof(message), &len)) == SQL_SUCCESS) { std::cerr << "ODBC Error: " << sqlstate << " - " << message << std::endl; i++; } } int main() { SQLHENV henv; SQLHDBC hdbc; SQLHSTMT hstmt; SQLRETURN retcode; // 1. 初始化 ODBC 环境 retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); checkODBCError(henv, SQL_HANDLE_ENV, retcode); retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); checkODBCError(henv, SQL_HANDLE_ENV, retcode); // 2. 建立数据库连接 retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); checkODBCError(hdbc, SQL_HANDLE_DBC, retcode); // 连接字符串(根据实际情况修改) SQLCHAR connStr[] = "DRIVER={SQL Server};SERVER=localhost;DATABASE=YourDB;UID=sa;PWD=your_password;"; retcode = SQLDriverConnect(hdbc, NULL, connStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE); checkODBCError(hdbc, SQL_HANDLE_DBC, retcode); // 3. 执行查询 retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); checkODBCError(hstmt, SQL_HANDLE_STMT, retcode); SQLCHAR* sqlQuery = (SQLCHAR*)"SELECT column1, column2 FROM YourTable"; retcode = SQLExecDirect(hstmt, sqlQuery, SQL_NTS); checkODBCError(hstmt, SQL_HANDLE_STMT, retcode); // 4. 读取结果集并保存到字符串 std::vector<std::string> results; SQLCHAR columnData[256]; SQLLEN indicator; while (SQLFetch(hstmt) == SQL_SUCCESS) { std::string rowData; // 逐列读取数据(假设读取两列) for (int col = 1; col <= 2; col++) { retcode = SQLGetData(hstmt, col, SQL_C_CHAR, columnData, sizeof(columnData), &indicator); if (retcode == SQL_SUCCESS && indicator != SQL_NULL_DATA) { rowData += reinterpret_cast<char*>(columnData); rowData += " | "; // 列分隔符 } else { rowData += "NULL | "; } } results.push_back(rowData); std::cout << "行数据: " << rowData << std::endl; } // 5. 释放资源 SQLFreeHandle(SQL_HANDLE_STMT, hstmt); SQLDisconnect(hdbc); SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); return 0; } ``` --- ### **关键函数说明** 1. **`SQLAllocHandle`** 分配 ODBC 环境、连接或语句句柄。 2. **`SQLDriverConnect`** 通过连接字符串建立到 SQL Server 的连接。 3. **`SQLExecDirect`** 执行 SQL 查询。 4. **`SQLFetch`** 逐行获取结果数据。 5. **`SQLGetData`** 将当前行的某一列数据转换为字符串格式。 --- ### **注意事项** 1. **连接字符串格式** 根据实际服务器地址、数据库名称、账号密码修改 `connStr`。例如: ```cpp "DRIVER={SQL Server};SERVER=127.0.0.1;DATABASE=TestDB;UID=user;PWD=123456;" ``` 2. **数据类型转换** - `SQLGetData` 的第三个参数 `SQL_C_CHAR` 表示将数据转换为字符串。 - 若列数据类型为整数、日期等,需调整转换方式(如 `SQL_C_LONG` 或 `SQL_C_TIMESTAMP`)。 3. **处理 NULL 值** 检查 `indicator` 是否为 `SQL_NULL_DATA`,避免读取无效数据。 4. **性能优化** - 使用参数化查询(`SQLBindParameter`)避免 SQL 注入。 - 批量读取数据时,可设置游标类型提升效率。 5. **依赖项配置** - 编译时需链接 ODBC 库(Windows 默认包含,Linux 需安装 `unixODBC`)。 - 代码中需包含 `sql.h` 和 `sqlext.h` 头文件。 --- ### **扩展:保存到字符串的格式** 可以将结果保存为以下格式: ```cpp // 单行示例 std::string row = "John | 25 | 2023-10-01"; // JSON 格式 std::string json = R"({"name": "John", "age": 25})"; // CSV 格式 std::string csv = "John,25,2023-10-01\nAlice,30,2023-10-02"; ``` 根据需求选择合适的数据格式,并在 `SQLGetData` 后拼接字符串。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值