最近在学习ADO与数据库的相关知识,现在我将自己学到的东西整理写出来,也算是对学习的一种复习。

这篇文章主要说明如何遍历某台机器上所有的数据库服务,遍历某个服务中所有的数据库,遍历数据库中的所有表以及表中所有字段字段,最后再说明如何通过ADO操作数据库中的表。

一、遍历所有数据库服务:

遍历数据库服务我们通过函数NetServerEnum来实现,该函数可以 遍历局域网中所有的服务可以通过指定服务类型来有筛选的进行枚举,以达到遍历所有数据库服务的目的,该函数的原型如下:


NET_API_STATUS NetServerEnum(
_In_opt_ LPCWSTR servername,
_In_ DWORD level,
_Out_ LPBYTE *bufptr,
_In_ DWORD prefmaxlen,
_Out_ LPDWORD entriesread,
_Out_ LPDWORD totalentries,
_In_ DWORD servertype,
_In_opt_ LPCWSTR domain,
_Inout_opt_ LPDWORD resume_handle
);

各个参数的说明如下:

servername:这个参数是系统保留的必须为NULL

level:参数用于指明返回参数的结构体的版本,主要有100和101两个值,分别对应SERVER_INFO_100和SERVER_INFO_100;

bufptr:是一个返回参数,系统在这个指针所指向的区域中填充一个SERVER_INFO_100或SERVER_INFO_100的结构体,具体使用哪一种由上一个参数指定;

prefmaxlen:返回值的最大长度,以字节为单位,一般我们设置为MAX_PREFREED_LENGHT,这个参数表明,具体需要多大的缓冲由函数指定

entriesread:由函数返回,表示当前获取的枚举的数量

totalentries:由函数返回,表示当前机器上所有的服务的总数

servertype:获取的服务的类型;(具体类型请参阅MSDN,我们这里主要用的是SV_TYPE_SQLSERVER获取数据库服务)

domain:一个常量字符串,用于指定要返回服务器列表域的名称,如果这个值为NULL则域名是隐含的

resume_handle:保留参数,该参数必须为NULL;

以下是实现的代码,大部分是从MSDN上Copy下来的,只是修改了小部分代码:

#include "stdafx.h"
#include
#include
#include
using namespace std;
#pragma comment(lib, "netapi32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
LPSERVER_INFO_101 pBuf = NULL;
LPSERVER_INFO_101 pTmpBuf;

DWORD dwLevel = 101;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwTotalCount = 0;
DWORD dwServerType = SV_TYPE_SQLSERVER; // SQL SERVER
DWORD dwResumeHandle = 0;
NET_API_STATUS nStatus;
LPWSTR pszServerName = NULL;
LPWSTR pszDomainName = NULL;
DWORD i;

nStatus = NetServerEnum(pszServerName, dwLevel, (LPBYTE *)&pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries, dwServerType,
pszDomainName, &dwResumeHandle);

if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
{
if ((pTmpBuf = pBuf) != NULL)
{
for (i = 0; i < dwEntriesRead; i++) //成功则依次输出结果
{
assert(pTmpBuf != NULL);
printf("\tPlatform: %d\n", pTmpBuf->sv101_platform_id);
wprintf(L"\tName: %s\n", pTmpBuf->sv101_name);
printf("\tVersion: %d.%d\n",pTmpBuf->sv101_version_major, pTmpBuf->sv101_version_minor);
printf("\tType: sql server");
printf("\n");
wprintf(L"\tComment: %s\n\n", pTmpBuf->sv101_comment);

pTmpBuf++;
dwTotalCount++;
}
}
else
{
printf("No servers were found\n");
printf("The buffer (bufptr) returned was NULL\n");
printf(" entriesread: %d\n", dwEntriesRead);
printf(" totalentries: %d\n", dwEntriesRead);
}

}
else//函数执行错误
{
fprintf(stderr, "NetServerEnum failed with error: %d\n", nStatus);
}
if (pBuf != NULL)
{
NetApiBufferFree(pBuf);//释放内存空间
}
}




二、遍历数据库中服务器中所有数据库:

通过上一步我们可以遍历局域网中所有数据库服务,这个时候我们更进一步来遍历数据库服务中所有的数据库,实现这个功能没有什么特殊的函数,主要是对系统表的应用,我们用的是系统表master.sys.database,该表中记录了服务中所有的数据库,通过ADO的方式来进行操作:

//初始化COM组件库
CoInitialize(NULL);
_ConnectionPtr pConnect;
HRESULT hErr;
try
{
//创建Connection对象
hErr = pConnect.CreateInstance("ADODB.Connection");
if (SUCCEEDED(hErr))
{
pConnect->Open("Driver={SQL Server};Server=LIUHAO-PC;Uid = sa;Pw = 1234", "", "", adModeUnknown);
}
}
catch (_com_error &e)
{
cout << e.Description() << endl;
}

try
{
//创建RECORD, COMMAND对象
_RecordsetPtr pRecord;
pRecord.CreateInstance("ADODB.Recordset");
_CommandPtr pCommand;
pCommand.CreateInstance("ADODB.Command");
//遍历服务器中所有数据库
cout << "服务器中所有数据库:" << endl;
pRecord->Open("select * from master.sys.databases", pConnect.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText);
_variant_t vName;
while (!pRecord->adoEOF)
{
vName = pRecord->GetCollect(_variant_t("name"));
wcout << (TCHAR*)_bstr_t(vName) << endl;
pRecord->MoveNext();
}
pRecord->Close();
}
catch
{
cout << e.Description() << endl;
}



三、遍历某个数据库中所有的表:

该操作也是使用系统表的内容,代码如下:

//遍历test数据库中所有表
cout << "数据库中所有表:" << endl;
pRecord->Open("use test SELECT name FROM sys.sysobjects WHERE type='U' ORDER BY name", pConnect.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText);
while (!pRecord->adoEOF)
{
vName = pRecord->GetCollect(_variant_t("name"));
wcout << (TCHAR*)_bstr_t(vName) << endl;
pRecord->MoveNext();
}
pRecord->Close();

sql语句中前面的"use test"表示在test数据库中查找表后面的“type = 'U' ”表示我们遍历的是用户表此外type 还可以是一下值:

U = 用户表

= 视图,
TF = 表函数,
P = 存储过程,
L = 日志

四、遍历某个表中的所有字段:

//显示表中所有的字段名
cout << "test表中所有字段:" << endl;
FieldsPtr fields;//用于保存字段信息
pRecord->Open("SELECT * FROM users", pConnect.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText);
fields = pRecord->GetFields();//获取字段信息
long nCount = fields->GetCount();//获取遍历到的字段总数
for (int i = 0; i < nCount; i++)
{//获取到的字段信息是放到field对象的item结构体数组中,利用GetItem可以获取该结构体数组中的某一项,利用GetName函数可以获取结构体中存储的字段名
bstr_t bstrName = (fields->GetItem(_variant_t((long)i)))->GetName();
TCHAR *pText = static_cast(bstrName);//将字段名转化为字符串输出
wcout << pText << endl;
}



利用以上所有代码,用户可以根据获取到局域网中所有SQL SERVER数据库服务器,遍历其中的所有数据库,根据获取到的数据库获取数据库中所有表,进到某一个表中遍历所有字段,有了字段用户就可以通过SQL语句操作某个表或者其中的某个字段了