在编程过程中,可能会遇到一些场景,直到运行时才知道数据库的模式。例如,即席查询和报告工具。在这些情况下,最终用户被允许从一系列表格中构建他们自己的SQL。正如可能已经知道的,通过ODBC执行SQL字符串并检索结果数据是非常容易的。但是,当在编写应用程序时不知道结果数据将是什么样子,该如何做呢?幸运的是,ODBC提供了几个函数,可以用于这个目的。在连接到数据源之后,接下来需要的步骤如下:
说过“幸运”吗?实际上,是带着讽刺的语气说的。因此,在本文中,向提交了一个类(CODBCDynamic),它将实现上述功能所需的400多行代码减少到2行代码!以下是如何使用CODBCDynamic类的示例。
本文还包括一个完整的测试应用程序,但在下载、解压缩和运行别人的代码之前,能够看到将获得什么总是很好的。因此,以下是一些代码片段,展示了CODBCDynamic类是多么容易使用。
要提交SQL语句,只需实例化一个CODBCDynamic对象(传递一个有效的DSN),然后调用CODBCDynamic::ExecuteSQL成员函数(传递要执行的SQL字符串)。就是这样!
CODBCDynamic odbcDynamic(_T("YourDsn"));
odbcDynamic.ExecuteSQL(_T("SELECT * from OrderHeader"));
在上面的第一个示例中,向展示了CODBCDynamic类如何允许使用ExecuteSQL成员函数提交SQL语句。然而,有时应用程序将只有HSTMT到结果集。例如,如果调用ODBC SDK函数SQLGetTypeInfo,将收到一个包含返回数据的结果集。使用CODBCDynamic类,可以使用以下两行代码将数据读取到其成员变量中。
odbcDynamic.FetchData(hstmt);
一旦调用了ExecuteSQL或FetchData成员函数,就可以以非常通用的方式从CODBCDynamic对象中检索结果数据。CODBCDynamic类有一个模板化数组(m_ODBCRecordArray),代表读取的每条记录。m_ODBCRecordArray中的每个条目是一个模板化的CMapStringToPtr映射,映射列及其在该记录中的相应值。该映射以列名(自动检索)为键,数据以CDBVariantEx对象的形式存在。
然而,永远不必担心这些技术细节。假设已经调用了ExecuteSQL或FetchData,以下是一个示例,展示了如何轻松地遍历SQL语句返回的记录。
CODBCDynamic odbcDynamic(_T("Forms Express System Database"));
odbcDynamic.ExecuteSQL(_T("SELECT * from UserMaster"));
CODBCRecordArray* pODBCRecordArray = &odbcDynamic.m_ODBCRecordArray;
CString strInfo;
for(int iRecord = 0; iRecord < pODBCRecordArray->GetSize(); iRecord++) {
CODBCRecord* pODBCRecord = (*pODBCRecordArray)[iRecord];
POSITION pos;
CDBVariantEx* pvarValue;
CString strColName;
CString strValue;
for(pos = pODBCRecord->GetStartPosition(); pos != NULL;) {
pODBCRecord->GetNextAssoc(pos, strColName, pvarValue);
pvarValue->GetStringValue(strValue);
strInfo.Format(_T("Record: %ld, Column: %s, Value: '%s'"), iRecord, strColName, strValue);
AfxMessageBox(strValue);
}
}
CODBCDynamic odbcDynamic(_T("Forms Express System Database"));
odbcDynamic.ExecuteSQL(_T("SELECT * from UserMaster"));
CODBCRecordArray* pODBCRecordArray = &odbcDynamic.m_ODBCRecordArray;
for(int iRecord = 0; iRecord < pODBCRecordArray->GetSize(); iRecord++) {
CODBCRecord* pODBCRecord = (*pODBCRecordArray)[iRecord];
CString strValue;
CDBVariantEx* pvarValue = NULL;
if(pODBCRecord->Lookup(_T("sUserId"), pvarValue)) {
pvarValue->GetStringValue(strValue);
AfxMessageBox(strValue);
// 或者,如果列的数据类型是字符串或文本...
AfxMessageBox(*pvarValue->m_pstring);
}
}