检索数据
若要通过 ODBC 检索数据,应执行将返回结果集的查询(例如 SELECT),然后使用以下两种方法之一检索结果:
-
使用
SQLFetch()
函数检索结果集的某个行,然后通过调用SQLGetData()
访问该行中的列值。 -
使用
SQLBindColumn()
函数将变量或数组绑定到结果集中的某个列,然后调用SQLExtendedFetch()
或SQLFetchScroll()
以读取结果集的某个行并将其值插入到该变量或数组中。
使用以上两种方法时,应在结果集中循环直至到达结尾(由 SQL_NO_DATA 返回状态指示)或遇到错误为止。
注意
Vertica 对每个连接仅支持一个游标。如果尝试对每个连接使用多个光标,将导致发生错误。例如,如果在其他语句的结果集处于打开状态时执行某个语句,您将收到错误。以下代码示例演示了如何通过以下过程从 Vertica 检索数据:
-
连接到数据库。
-
执行将返回所有表的 ID 和名称的 SELECT 语句。
-
将两个变量绑定到结果集中的两个列。
-
在结果集中循环,并输出 ID 和名称值。
// Demonstrate running a query and getting results by querying the tables
// system table for a list of all tables in the current schema.
// Some standard headers
#include <stdlib.h>
#include <sstream>
#include <iostream>
#include <assert.h>
// Standard ODBC headers
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
// Use std namespace to make output easier
using namespace std;
// Helper function to print SQL error messages.
template <typename HandleT>
void reportError(int handleTypeEnum, HandleT hdl)
{
// Get the status records.
SQLSMALLINT i, MsgLen;
SQLRETURN ret2;
SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
SQLINTEGER NativeError;
i = 1;
cout << endl;
while ((ret2 = SQLGetDiagRec(handleTypeEnum, hdl, i, SqlState, &NativeError,
Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
cout << "error record #" << i++ << endl;
cout << "sqlstate: " << SqlState << endl;
cout << "detailed msg: " << Msg << endl;
cout << "native error code: " << NativeError << endl;
}
}
typedef struct {
SQLHENV hdlEnv;
SQLHDBC hdlDbc;
} DBConnection;
void connect(DBConnection *pConnInfo)
{
// Set up the ODBC environment
SQLRETURN ret;
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &pConnInfo->hdlEnv);
assert(SQL_SUCCEEDED(ret));
// Tell ODBC that the application uses ODBC 3.
ret = SQLSetEnvAttr(pConnInfo->hdlEnv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3, SQL_IS_UINTEGER);
assert(SQL_SUCCEEDED(ret));
// Allocate a database handle.
ret = SQLAllocHandle(SQL_HANDLE_DBC, pConnInfo->hdlEnv, &pConnInfo->hdlDbc);
assert(SQL_SUCCEEDED(ret));
// Connect to the database
cout << "Connecting to database." << endl;
const char* dsnName = "ExampleDB";
const char* userID = "dbadmin";
const char* passwd = "password123";
ret = SQLConnect(pConnInfo->hdlDbc, (SQLCHAR*)dsnName,
SQL_NTS, (SQLCHAR*)userID, SQL_NTS,
(SQLCHAR*)passwd, SQL_NTS);
if (!SQL_SUCCEEDED(ret)) {
cout << "Could not connect to database" << endl;
reportError<SQLHDBC>(SQL_HANDLE_DBC, pConnInfo->hdlDbc);
exit(EXIT_FAILURE);
}
else {
cout << "Connected to database." << endl;
}
}
void disconnect(DBConnection *pConnInfo)
{
SQLRETURN ret;
// Clean up by shutting down the connection
cout << "Free handles." << endl;
ret = SQLDisconnect(pConnInfo->hdlDbc);
if (!SQL_SUCCEEDED(ret)) {
cout << "Error disconnecting. Transaction still open?" << endl;
exit(EXIT_FAILURE);
}
SQLFreeHandle(SQL_HANDLE_DBC, pConnInfo->hdlDbc);
SQLFreeHandle(SQL_HANDLE_ENV, pConnInfo->hdlEnv);
}
void executeQuery(SQLHDBC hdlDbc, SQLCHAR* pQuery)
{
SQLRETURN ret;
// Set up a statement handle
SQLHSTMT hdlStmt;
SQLAllocHandle(SQL_HANDLE_STMT, hdlDbc, &hdlStmt);
assert(SQL_SUCCEEDED(ret));
// Execute a query to get the names and IDs of all tables in the schema
// search p[ath (usually public).
ret = SQLExecDirect(hdlStmt, pQuery, SQL_NTS);
if (!SQL_SUCCEEDED(ret)) {
// Report error an go no further if statement failed.
cout << "Error executing statement." << endl;
reportError<SQLHDBC>(SQL_HANDLE_STMT, hdlStmt);
exit(EXIT_FAILURE);
}
else {
// Query succeeded, so bind two variables to the two colums in the
// result set,
cout << "Fetching results..." << endl;
SQLBIGINT table_id; // Holds the ID of the table.
SQLTCHAR table_name[256]; // buffer to hold name of table
ret = SQLBindCol(hdlStmt, 1, SQL_C_SBIGINT, (SQLPOINTER)&table_id,
sizeof(table_id), NULL);
ret = SQLBindCol(hdlStmt, 2, SQL_C_TCHAR, (SQLPOINTER)table_name,
sizeof(table_name), NULL);
// Loop through the results,
while (SQL_SUCCEEDED(ret = SQLFetchScroll(hdlStmt, SQL_FETCH_NEXT, 1))) {
// Print the bound variables, which now contain the values from the
// fetched row.
cout << table_id << " | " << table_name << endl;
}
// See if loop exited for reasons other than running out of data
if (ret != SQL_NO_DATA) {
// Exited for a reason other than no more data... report the error.
reportError<SQLHDBC>(SQL_HANDLE_STMT, hdlStmt);
}
}
SQLFreeHandle(SQL_HANDLE_STMT, hdlStmt);
}
int main()
{
DBConnection conn;
connect(&conn);
executeQuery(conn.hdlDbc,
(SQLCHAR*)"SELECT table_id, table_name FROM tables ORDER BY table_name");
executeQuery(conn.hdlDbc,
(SQLCHAR*)"SELECT table_id, table_name FROM tables ORDER BY table_id");
disconnect(&conn);
exit(EXIT_SUCCESS);
}
在 vmart 数据库中运行以上示例代码后,将生成类似于以下内容的输出:
Connecting to database.
Connected to database.
Fetching results...
45035996273970908 | call_center_dimension
45035996273970836 | customer_dimension
45035996273972958 | customers
45035996273970848 | date_dimension
45035996273970856 | employee_dimension
45035996273970868 | inventory_fact
45035996273970904 | online_page_dimension
45035996273970912 | online_sales_fact
45035996273970840 | product_dimension
45035996273970844 | promotion_dimension
45035996273970860 | shipping_dimension
45035996273970876 | store_dimension
45035996273970894 | store_orders_fact
45035996273970880 | store_sales_fact
45035996273972806 | t
45035996273970852 | vendor_dimension
45035996273970864 | warehouse_dimension
Fetching results...
45035996273970836 | customer_dimension
45035996273970840 | product_dimension
45035996273970844 | promotion_dimension
45035996273970848 | date_dimension
45035996273970852 | vendor_dimension
45035996273970856 | employee_dimension
45035996273970860 | shipping_dimension
45035996273970864 | warehouse_dimension
45035996273970868 | inventory_fact
45035996273970876 | store_dimension
45035996273970880 | store_sales_fact
45035996273970894 | store_orders_fact
45035996273970904 | online_page_dimension
45035996273970908 | call_center_dimension
45035996273970912 | online_sales_fact
45035996273972806 | t
45035996273972958 | customers
Free handles.