总体来说VS有两种配置SQL Server的方式,一种是ADO,另一种是ODBC。这两种方式的查询我都有问题,查询到了结果数据不是乱码就是显示在list control上时值变了,我也不知道为什么。
ADO
1 什么是ADO
以下ADO概念引用自 ADO数据库访问技术_lishan9133的博客-CSDN博客
ADO(active data object,活动数据对象),是一种基于COM(组件对象模型)的自动化接口技术,并以OLE DB(对象连接和镶入的数据库)为基础,经过OLE DB精心包装后的数据库访问技术,利用它可以快速的创建数据库应用程序。ADO提供了一组非常简单,将一般通用的数据访问细节进行封装的对象。由于ODBC数据源也提供了一般的OLE DB Privider,所以ADO不仅可以应用自身的OLE DB Privider,而且还可以应用所有的ODBC驱动程序。
2 步骤
1 引入ADO库文件,初始化COM组件
2 声明Connection实例对象,并连接(打开)数据库
3 利用连接对象 进行数据库操作
4 结束操作,关闭连接,释放连接对象
3 引入ADO库文件
#import "C:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("EOF","adoEOF")
这个路径下的msado.dll文件是已经存在的,不需要安装或者下载其他软件或库文件。有三点需要注意,也相当于四个问题吧。
第一:需要将外部文件引入到头文件中,在某个版本之后VS版本中pch.h就代替了那个s开头的头文件,这个无关紧要。
第二:引入这个文件路径的时候,VS编译器可能会报错,声称找不到这个文件,通过网上查找发现这个问题并不需要解决。也就是说出现这个BUG可能是编译器自己反应慢,这个错误在编译的时候也可以通过。
第三: no_namespace rename("EOF","adoEOF") 这条语句的作用是防止与其他库名中的EOF冲突。这里就不得不讲一讲EOF 和BOF了。BOF 指示当前记录位置位于记录集对象的第一个记录之前;EOF 指示当前记录位置位于记录集对象的最后一个记录之后。他们都是布尔值,即:只能为 True 或者 False。他们被用于判断记录指针是否越界,如果越界操作,程序运行会产生错误。如果没有打开记录集对象,BOF 和 EOF 都被设置为 True,RecordCount 属性值为 0;如果打开的记录集对象中至少包含一条记录,则第一条记录为当前记录,BOF 和 EOF 属性都为 False。
第四: 有些情况下会出现4996的错误,网上查找会有以下代码解决
项目属性->C/C++->SDL检查->关闭 ,然后在头文件定义之后再加上以下语句
#pragma warning(disable:4996)
4 初始化COM组件
HRESULT hr=CoInitialize(NULL);//ADO是COM组件,所以使用ADO连接数据库需要初始化COM组件
ASSERT(SUCCEEDED(hr)); //SUCCEEDED(hr)先判断COM是否初始化成功,如果不成功ASSERT的参数即为假,则会报告错误并终止程序
5 声明实例对象指针
_ConnectionPtr pMyConnect; //连接对象指针
_RecordsetPtr pRecord; //记录集对象指针
_CommandPtr pCommand; //命令对象指针
Connection对象:它表示到数据库的连接,管理应用程序和数据库之间的通信。Command和Recordset对象都有一个ActiveConnection属性,该属性用来引用Connection对象。
Command对象:被用来处理重复执行的查询,或处理需要检查在存储过程调用中的输出或返回参数的值的查询。
Recordset对象:被用来获取数据。Recordset对象存放查询的结果,这些结果由数据的行(成为记录)和列(称为字段)组成。每一列都存放在Recordset的Fields集合中的一个Fields对象中。
6 连接数据库
try {
pMyConnect.CreateInstance(__uuidof(Connection));
pRecord.CreateInstance(__uuidof(Recordset));
pMyConnect->Open("Provider=SQLOLEDB;Server=192.168.100.200;Database=TEST;uid=sa;pwd=123", "", "", adModeUnknown);
}
catch (_com_error& e)
{
AfxMessageBox(e.Description()+e.HelpFile());
return;
}
这里创建了连接实例和记录集实例,并用调用了Open函数打开了数据库
第一个参数:连接字符串。这个字符串可以自己获取。在电脑的任意位置文本,并修改为以udl后缀的文件。
双击打开后 输入自己想要连接的数据库信息,然后再改回文本文件双击打开,第二行就是我们需要的内容了,下面随便给大家做个示例。如果想要显示密码那么就需要选中允许保存密码选项。
后面几个参数
adModeUnknown:缺省。当前的许可权未设置
adModeRead:只读
adModeWrite:只写
adModeReadWrite:可以读写
adModeShareDenyRead:阻止其它Connection对象以读权限打开连接
adModeShareDenyWrite:阻止其它Connection对象以写权限打开连接
adModeShareExclusive:阻止其它Connection对象以读写权限打开连接
adModeShareDenyNone:阻止其它Connection对象以任何权限打开连接
Connection对象除Open()方法外还有许多方法,我们先介绍Connection对象中两个有用的属性ConnectionTimeOut与State。ConnectionTimeOut用来设置连接的超时时间,需要在Open之前调用,例如:
m_pConnection->ConnectionTimeout = 5;///设置超时时间为5秒 m_pConnection->Open("Data Source=adotest;","","",adModeUnknown);
7 进行数据库操作
因为我是MFC程序,所以我就直接上完整代码了
//连接数据库
void CADOMFCDlg::OnBnClickedConnectButton()
{
HRESULT hr=CoInitialize(NULL);//ADO是COM组件,所以使用ADO连接数据库需要初始化COM组件
ASSERT(SUCCEEDED(hr)); //SUCCEEDED(hr)先判断COM是否初始化成功,如果不成功ASSERT的参数即为假,则会报告错误并终止程序
//_ConnectionPtr p(__uuidof(Connection));
//pMyConnect = p;
//_RecordsetPtr pRst(__uuidof(Recordset));//定义记录集对象并实例化对象
//pRecord = pRst;
try {
pMyConnect.CreateInstance(__uuidof(Connection));
pRecord.CreateInstance(__uuidof(Recordset));
pMyConnect->Open("Provider=SQLOLEDB;Server=192.168.100.200;Database=TEST;uid=sa;pwd=123", "", "", adModeUnknown);
}
catch (_com_error& e)
{
AfxMessageBox(e.Description()+e.HelpFile());
return;
}
TODO: 在此添加额外的初始化代码
CRect rect;
//showList.DeleteAllItems();
// 获取编程语言列表视图控件的位置和大小
showMessage.GetClientRect(rect);
为列表视图控件添加全行选中和栅格风格
showMessage.SetExtendedStyle(showMessage.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
// 为列表视图控件添加三列
showMessage.InsertColumn(0, _T("ID"), LVCFMT_CENTER, rect.Width() / 5);
showMessage.InsertColumn(1, _T("姓名"), LVCFMT_CENTER, rect.Width() / 5);
showMessage.InsertColumn(2, _T("性别"), LVCFMT_CENTER, rect.Width() / 5);
showMessage.InsertColumn(3, _T("年龄"), LVCFMT_CENTER, rect.Width() / 5);
showMessage.InsertColumn(4, _T("地址"), LVCFMT_CENTER, rect.Width() / 5);
connectButton.EnableWindow(0);
disConnectButton.EnableWindow(1);
AfxMessageBox(L"数据库连接成功");
}
void CADOMFCDlg::OnBnClickedCloseButton()
{
try
{
pMyConnect->Close();//关闭数据库
pRecord.Release(); //释放记录集对象指针
pMyConnect.Release();//释放连接对象指针
pMyConnect = NULL;
pRecord = NULL;
::CoUninitialize();
}
catch (_com_error& e)
{
/*wchar_t buf[128];
swprintf(buf, L"错误描述:%s 错误帮助:%s", e.Description(), e.HelpFile());
AfxMessageBox(buf);*/
AfxMessageBox(e.Description() + e.HelpFile());
return;
}
connectButton.EnableWindow(1);
disConnectButton.EnableWindow(0);
AfxMessageBox(L"数据库关闭成功");
}
void CADOMFCDlg::OnBnClickedInsertButton()
{
// TODO: 在此添加控件通知处理程序代码
CString insertSql,ID,Name,Sex,Age,Address;
GetDlgItemText(IDC_ID_EDIT,ID);
if (ID == "")
{
AfxMessageBox(L"请输入ID");
return;
}
GetDlgItemText(IDC_NAME_EDIT, Name);
GetDlgItemText(IDC_AGE_EDIT, Age);
GetDlgItemText(IDC_ADDRESS_EDIT, Address);
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck())
Sex = "man";
if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck())
Sex = "woman";
int id = _ttoi(ID);
int age = _ttoi(Age);
insertSql.Format(L"insert into Student values('%d','%s','%s','%d','%s')",id, Name, Sex, age, Address);
_RecordsetPtr pRecord;
try {
pRecord = pMyConnect->Execute((_bstr_t)insertSql, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
AfxMessageBox(L"插入数据成功");
}
这里我的变更条件就是ID name sex age address 可选项,目前只写了一个ID 的。
//更新数据
void CADOMFCDlg::OnBnClickedUpdateButton()
{
// TODO: 在此添加控件通知处理程序代码
if (pMyConnect == NULL)
{
AfxMessageBox(L"请先连接数据库后再操作");
return;
}
int nIndex = condition.GetCurSel();
CString con;
CString ID, Name, Sex, Age, Address;
condition.GetLBText(nIndex, con);
//获取 需要修改数据
GetDlgItemText(IDC_ID_EDIT, ID);
GetDlgItemText(IDC_NAME_EDIT, Name);
GetDlgItemText(IDC_AGE_EDIT, Age);
GetDlgItemText(IDC_ADDRESS_EDIT, Address);
if (((CButton*)GetDlgItem(IDC_RADIO1))->GetCheck())
Sex = "man";
else if (((CButton*)GetDlgItem(IDC_RADIO2))->GetCheck())
Sex = "woman";
else Sex = "";
int id = _ttoi(ID);
int age = _ttoi(Age);
//获取 需要修改的条件
if (con == "ID")
{
CString updateSql1, updateSql2,updateSql3,updateSql4;
if (ID == "")
{
AfxMessageBox(L"无法对空ID作出更新");
return;
}
else if ( Name == "" && Age == "" && Sex == "" && Address == "")
{
AfxMessageBox(L"未作出任何修改");
return;
}
CString selectID;
selectID.Format(L"select * from Student where ID='%d'", _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)selectID, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
if (pRecord->adoEOF)
{
AfxMessageBox(L"无法对不存在的ID作出修改");
return;
}
if (Name != "")
{
updateSql1.Format(L"update Student set name ='%s' where ID='%d'", Name, _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)updateSql1, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
}
if (Sex != "")
{
updateSql2.Format(L"update Student set sex ='%s' where ID='%d'", Sex, _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)updateSql2, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
}
if (Age != "")
{ updateSql3.Format(L"update Student set age ='%s' where ID='%d'", Age, _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)updateSql3, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
}
if (Address != "")
{
updateSql4.Format(L"update Student set address ='%s' where ID='%d'", Address, _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)updateSql4, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
}
AfxMessageBox(L"根据ID数据修改成功");
}
}
//删除数据
void CADOMFCDlg::OnBnClickedDeleteButton()
{
// TODO: 在此添加控件通知处理程序代码
if (pMyConnect == NULL)
{
AfxMessageBox(L"请先连接数据库后再操作");
return;
}
CString deleteSql,ID;
GetDlgItemText(IDC_ID_EDIT, ID);
if (ID =="")
{
AfxMessageBox(L"请输入ID后重试");
return;
}
CString selectID;
selectID.Format(L"select * from Student where ID='%d'", _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)selectID, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
if (pRecord->adoEOF)
{
AfxMessageBox(L"无法删除不存在的ID");
return;
}
deleteSql.Format(L"delete from Student where ID ='%d'", _ttoi(ID));
try {
pRecord = pMyConnect->Execute((_bstr_t)deleteSql, NULL, adCmdText);
}
catch (_com_error e) {
AfxMessageBox(e.ErrorMessage());
return;
}
AfxMessageBox(L"数据删除成功");
}
//查询
void CADOMFCDlg::OnBnClickedSelectButton()
{
showMessage.DeleteAllItems();
_bstr_t sqlSelect = "select * from Student"; //查询Studnet表里的数据
if (pMyConnect == NULL)
{
AfxMessageBox(L"请连接数据库后再操作");
return;
}
int i = 0;
wchar_t* id, * name, * sex, * address, * age;
pRecord->Open(sqlSelect, pMyConnect.GetInterfacePtr(), adOpenDynamic, adLockOptimistic, adCmdText);
//pRecord = pMyConnect->Execute(sqlSelect , NULL, adCmdText); //获取记录集
if (!pRecord->BOF)
pRecord->MoveFirst();
else
{
AfxMessageBox(L"数据表为空");
return;
}
while (!pRecord->adoEOF)
{
id = (wchar_t*)(_bstr_t)pRecord->GetCollect(_T("ID"));
name = (wchar_t*)(_bstr_t)pRecord->GetCollect(_T("name"));
sex = (wchar_t*)(_bstr_t)pRecord->GetCollect(_T("sex"));
age = (wchar_t*)(_bstr_t)pRecord->GetCollect(_T("age"));
address = (wchar_t*)(_bstr_t)pRecord->GetCollect(_T("address"));
showMessage.InsertItem(i, _T(""));
showMessage.SetItemText(i, 0, id); //添加到list Control 中的第i行的第一列下
showMessage.SetItemText(i, 1, name); //添加到list Control 中的第i行的第二列下
showMessage.SetItemText(i, 2, sex); //添加到list Control 中的第i行的第三列下
showMessage.SetItemText(i, 3, age); //添加到list Control 中的第i行的第四列下
showMessage.SetItemText(i, 4, address);
i += 1; //下次循环指向第2行
pRecord->MoveNext(); //移动到下一个记录
}
pRecord->Close();
}
ODBC
1 什么是ODBC
开放数据库连接(ODBC)是微软提出的数据库访问接口标准。用微软管阀的话来说就是:ODBC 是数据库 API 的规范。任何人都可以编写 ODBC 应用程序和驱动程序。使用 ODBC 的应用程序负责任何跨数据库功能。 例如,ODBC 不是异类联接引擎,也不是分布式事务处理器。 但是,由于它是与 DBMS 无关的,因此可用于生成此类跨数据库工具。
2 步骤
1 sql Server 创建数据库和表
2 ODBC创建数据源
3 VS配置数据源
4 VS连接数据源 (连接数据库)
5 VS访问数据源(实现增删改查)
3 sql Server 创建数据库和表
为了方便测试,我创建了一个最常见的student数据库和student信息表,如下图
4 创建数据源
1 在搜索栏搜索ODBC,这里我选择64位,最好与自己的VS编译版本和sql server版本一致。
2 点击添加
3 找到自己需要的数据库 数据源类型
4 编辑自己的数据源,这个在代码编写的时候会使用。 服务器填的是自己数据库所在的电脑IP地址,如果是本地就可以设置为127.0.0.1。
5 点击下一页 选择红框选项,并输入自己的sql server配置的sa 和密码
6 如果配置正确 就会进到下一个页面,默认下一步就好
7 点击测试数据源
8 出现下图就是数据源创建成功了,就可以准备代码了。
刚才说到配置正确才会进到下一步,如果sql server 安装失败或者配置失败就会出现下图类似的错误,至于解决方案,我的建议是重装,至于是装软件还是装机看个人运气。
5 VS配置数据源
1 vs 连接数据库 工具->连接到数据库
2 如果是第一次使用 会弹出安装插件的提示,点击确定
3 单击安装
4 安装完成 重复步骤一
5 连接设置
选择SQL Server身份验证并输入自己设定的sa和密码。下方的数据库名可以选择自己创建的数据库,
这样在应用中就默认打开我们设置的数据库,也可以不设置。
配置成功后就可以在服务资源管理器中看到我们的数据库和表了
6 vs 连接数据源
这里要知道一些概念和操作
1 句柄
本部分参考 以下前辈的博客(162条消息) 【ODBC】ODBC连接数据库详细说明_yzzheng_60125的博客-CSDN博客
应用程序运行后,为维护执行的状态,ODBC 管理器和ODBC 驱动程序中必须保持足够的控制信息。应用程序要求ODBC 管理器和ODBC 驱动程序为ODBC环境、每个连接以及每个SQL语句分配描述/控制信息存储空间,并返回指向各个存储区的句柄供其使用。
(1)环境句柄:整个ODBC上下文的根句柄。标识全程数据访问控制信息的内存结构,包括有效连接句柄以及当前活动连接句柄。ODBC将环境句柄定义为HENV类型的变量。应用程序使用单一的环境句柄,在连接到数据源以前必须申请该句柄。
(2)连接句柄:管理有关数据库会话的所有信息。连接句柄标识每个特定的连接信息的内存结构。ODBC将环境句柄定义为HDBC类型的变量。应用程序在连接数据源之前申请连接句柄。每个连接句柄与环境句柄有关,环境句柄上可以有多个与其有关的连接句柄。
(3)语句句柄:ODBC语句包括应用访问数据源的SQL语句和语句相关的管理信息,语句句柄标识每个语句管理信息的内存结构。ODBC将语句句柄定义为HSTMT类型的变量。应用程序在提交SQL请求之前也必须申请语句句柄。每个语句句柄与一个连接句柄有关,每个连接句柄上可以有多个与其有关的语句句柄。
这里大家也应该明白了,一个应用程序有一个环境句柄,用来给ODBC提供环境支持,在这个环境句柄上有多个连接句柄,用来管理数据库和标识数据库结构,每个环境句柄上又有多个语句句柄可以访问数据源。可以这样理解,但是肯定有偏差。
ODBC通过SQLAllocHandle来分配句柄
SQLRETURN ret;//返回信息
SQLHENV henv;//环境句柄 可以理解为申请并配置ODBC环境
SQLHDBC hdbc;//连接句柄 可以理解为申请数据库连接
SQLHSTMT hstmt;//语句句柄 可以理解为执行sql语句访问数据源
环境句柄 | SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) |
连接句柄 | SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) |
语句句柄 | SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt)或者SQLAllocStmt(hdbc, hstmt) |
2 连接数据库
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);//申请环境句柄
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);//设置环境句柄
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);//申请数据库连接
ret = SQLConnect(hdbc, L"test", SQL_NTS, L"sa", SQL_NTS, L"你自己设置的密码", SQL_NTS);
if ((ret == SQL_SUCCESS) || (ret == SQL_SUCCESS_WITH_INFO))
{
AfxMessageBox(L"数据库成功打开");
}
else
{
AfxMessageBox(L"打开数据库失败");
}
上述代码中SQLConnect 函数的作用就是连接数据源的数据库
参数含义: hdbc--连接句柄
test--数据源名称 ,根据个人添加的源名称
SQL_NTS--数据源名称的长度,用户名长度,密码长度
sa--用户名,根据个人设置
"你自己设置的密码"-- sa的密码
字符串前加L的含义:
文章参考前辈博客
字符串 前 L的含义_字符串前加l_whz_zb的博客-CSDN博客
一、 在字符串前加一个L作用: unicode字符集是两个字节组成的。L告示编译器使用两个字节的 unicode 字符集。
如 L"我的字符串" 表示将ANSI字符串转换成unicode的字符串,就是每个字符占用两个字节。
strlen("asd") = 3;
strlen(L"asd") = 6;
二、 _T宏可以把一个引号引起来的字符串,根据你的环境设置,使得编译器会根据编译目标环境选择合适的(Unicode还是ANSI)字符处理方式
如果你定义了UNICODE,那么_T宏会把字符串前面加一个L。这时 _T("ABCD") 相当于 L"ABCD" ,这是宽字符串。
如果没有定义,那么_T宏不会在字符串前面加那个L,_T("ABCD") 就等价于 "ABCD"
返回值:系统宏定义的防护值 这俩种情况就是成功
3 关闭数据库
我个人认为释放句柄是有顺序的,因为一对多的关系,所以要反着释放,当然只是我个人的认为
释放语句句柄 | SQLFreeHandle(SQL_HANDLE_STMT, hstmt)或者SQLFreeStmt(hstmt, SQL_DROP) |
释放连接句柄 | SQLFreeHandle(SQL_HANDLE_DBC, hdbc)或者SQLDisconnect(hdbc)与SQLFreeConnect(hdbc) |
释放环境句柄 | SQLFreeHandle(SQL_HANDLE_ENV, henv)或者SQLFreeEnv(henv) |
7 VS访问数据源(实现增删改查)
1 增加
//一些变量的定义在前文已经说明了
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请语句句柄
CString str1 = L"use student";//use 【你的数据库名称】
CString str2 = L"insert into Student values ('1','Bob', '18', '男', 'China')";//要执行的SQL语句
ret = SQLExecDirect(hstmt, (SQLWCHAR *)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
AfxMessageBox(L"插入数据成功");
}
else {
AfxMessageBox(L"插入数据失败");
}
效果
2 删除
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请句柄
CString str1 = L"use student";
CString str2 = L"delete from student where name ='Bob'";
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
AfxMessageBox(L"数据删除成功");
}
else {
AfxMessageBox(L"数据删除失败,请检查表中是否有此数据");
}
3 修改
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请句柄
CString str1 = L"use studnet";
CString str2 = L"update student set address ='济南' where name ='Bob'";
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
AfxMessageBox(L"数据修改成功");
}
else {
AfxMessageBox(L"数据删除失败,请检查表中是否有此数据");
}
4 查找
引用部分以下前辈博客内容
(162条消息) 【ODBC】ODBC连接数据库详细说明_yzzheng_60125的博客-CSDN博客
SQLFetch函数的功能是将结果集的当前记录指针移至下一个记录;
SQLGetData函数的功能是提取结果集中当前记录的某个字段值。通常可以采用一个循环以提取结果集中所有记录的所有字段值,该循环重复执行SQLFetch和SQLGetData函数,直至SQLFetch函数返回SQL_NO_DATA_FOUND, 这表示已经到达结果集的末尾。
因为我用的是MFC程序 ,用到了 List control 控件 我的查询结果放在了这个控件上
message_list.DeleteAllItems();
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请句柄
CString str1 = L"use student";
CString str2 = L"select * from student";
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
int i = 0;
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
while (SQLFetch(hstmt) != SQL_NO_DATA)
{
SQLWCHAR str1[10], str2[12], str3[20], str4[20],str5[20];
SQLLEN len_str1, len_str2, len_str3, len_str4,len_str5;
SQLGetData(hstmt, 1, SQL_C_CHAR, str1, 10, &len_str1); //获取第一列数据
SQLGetData(hstmt, 2, SQL_C_CHAR, str2, 12, &len_str2);
SQLGetData(hstmt, 3, SQL_C_CHAR, str3, 20, &len_str3);
SQLGetData(hstmt, 4, SQL_C_CHAR, str4, 20, &len_str4);
SQLGetData(hstmt, 5, SQL_C_CHAR, str5, 20, &len_str5);
message_list.InsertItem(i, _T(""));
message_list.SetItemText(i, 0, str1); //添加到list Control 中的第i行的第一列下
message_list.SetItemText(i, 1, str2); //添加到list Control 中的第i行的第二列下
message_list.SetItemText(i, 2, str3); //添加到list Control 中的第i行的第三列下
message_list.SetItemText(i, 3, str4); //添加到list Control 中的第i行的第四列下
message_list.SetItemText(i, 4, str5); //添加到list Control 中的第i行的第五列下
i++;
}
}
else {
AfxMessageBox(L"数据删除失败,请检查表中是否有此数据");
}
MFC部分代码
void CtestSqlServerDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);//申请环境句柄
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);//设置环境句柄
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);//申请数据库连接
ret = SQLConnect(hdbc, L"test", SQL_NTS, L"sa", SQL_NTS, L"zyzb1234!", SQL_NTS);
if ((ret == SQL_SUCCESS) || (ret == SQL_SUCCESS_WITH_INFO))
{
AfxMessageBox(L"数据库成功打开");
//用于获取list control的尺寸
CRect rect;
//获取控件尺寸
message_list.GetClientRect(rect);
//风格设计
message_list.SetExtendedStyle(message_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
//创建表格字段
message_list.InsertColumn(0, _T("ID"), LVCFMT_CENTER, rect.Width() / 5, 0);
message_list.InsertColumn(1, _T("姓名"), LVCFMT_CENTER, rect.Width() / 5, 1);
message_list.InsertColumn(2, _T("性别"), LVCFMT_CENTER, rect.Width() / 5, 2);
message_list.InsertColumn(3, _T("年龄"), LVCFMT_CENTER, rect.Width() / 5, 3);
message_list.InsertColumn(4, _T("地址"), LVCFMT_CENTER, rect.Width() / 5, 4);
btn_connect.EnableWindow(0);
btn_disconnect.EnableWindow(1);
}
else
{
AfxMessageBox(L"打开数据库失败");
}
/*if (!my_dataBase.Open(NULL, FALSE, FALSE, L"ODBC;DSN=test;UID=sa;PWD=123"))
{
AfxMessageBox(L"打开数据库失败");
}
else
{
AfxMessageBox(L"数据库成功打开");
}*/
}
//插入数据
void CtestSqlServerDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请语句句柄
CString str1 = L"use student";//use 【你的数据库名称】
CString str2 = L"insert into Student values ('1','Bob', '18', '男', 'China')";//要执行的SQL语句
ret = SQLExecDirect(hstmt, (SQLWCHAR *)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
AfxMessageBox(L"插入数据成功");
}
else {
AfxMessageBox(L"插入数据失败");
}
/* CString insertSQL = L"insert into Student values ('1','zhangsan','man','18','China')";
my_dataBase.ExecuteSQL(insertSQL);
*/
}
//删除数据
void CtestSqlServerDlg::OnBnClickedButton4()
{
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请句柄
CString str1 = L"use student";
CString str2 = L"delete from student where name ='Bob'";
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
AfxMessageBox(L"数据删除成功");
}
else {
AfxMessageBox(L"数据删除失败,请检查表中是否有此数据");
}
}
//修改数据
void CtestSqlServerDlg::OnBnClickedButton3()
{
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请句柄
CString str1 = L"use studnet";
CString str2 = L"update student set address ='济南' where name ='Bob'";
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
AfxMessageBox(L"数据修改成功");
}
else {
AfxMessageBox(L"数据删除失败,请检查表中是否有此数据");
}
}
//查询数据
void CtestSqlServerDlg::OnBnClickedButton5()
{
message_list.DeleteAllItems();
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);//申请句柄
CString str1 = L"use student";
CString str2 = L"select * from student";
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str1.GetBuffer(), SQL_NTS);
ret = SQLExecDirect(hstmt, (SQLWCHAR*)str2.GetBuffer(), SQL_NTS);
int i = 0;
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
while (SQLFetch(hstmt) != SQL_NO_DATA)
{
SQLWCHAR str1[10], str2[12], str3[20], str4[20],str5[20];
SQLLEN len_str1, len_str2, len_str3, len_str4,len_str5;
SQLGetData(hstmt, 1, SQL_C_CHAR, str1, 10, &len_str1); //获取第一列数据
SQLGetData(hstmt, 2, SQL_C_CHAR, str2, 12, &len_str2);
SQLGetData(hstmt, 3, SQL_C_CHAR, str3, 20, &len_str3);
SQLGetData(hstmt, 4, SQL_C_CHAR, str4, 20, &len_str4);
SQLGetData(hstmt, 5, SQL_C_CHAR, str5, 20, &len_str5);
message_list.InsertItem(i, _T(""));
message_list.SetItemText(i, 0, str1); //添加到list Control 中的第i行的第一列下
message_list.SetItemText(i, 1, str2); //添加到list Control 中的第i行的第二列下
message_list.SetItemText(i, 2, str3); //添加到list Control 中的第i行的第三列下
message_list.SetItemText(i, 3, str4); //添加到list Control 中的第i行的第四列下
message_list.SetItemText(i, 4, str5); //添加到list Control 中的第i行的第五列下
i++;
}
}
else {
AfxMessageBox(L"数据删除失败,请检查表中是否有此数据");
}
}
//断开连接
void CtestSqlServerDlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
//my_dataBase.Close();
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);//释放语句
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);//释放连接
SQLFreeHandle(SQL_HANDLE_ENV, henv);//释放环境
AfxMessageBox(L"数据库关闭成功");
/*btn_connect.EnableWindow(1);
btn_disconnect.EnableWindow(0);*/
}