文章目录
- 整体总结
- ODBC连接
- 一个修改别人的整体的例子
整体总结
用odbc过时了,还是使用ado吧,易用,高效率,不用配置odbc数据源,易维护,实际项目已从odbc中改用了ado,
参考官网:https://docs.microsoft.com/zh-cn/sql/odbc/reference/syntax/sqlallochandle-function?view=sql-server-ver15
ODBC访问sql server数据库,比较麻烦。没有像使用occi那样访问oracle数据库那么方便(lsl20200817修正:occi访问oracle获取股票列表并不见得有多快,目前只是觉得能用就不改进了)。 批量操作并不好。如获取数据,执行sql后,还需要循环一个个取数据,很是麻烦,需要输入要获取的数据的类型。
可以所有列都是按SQL_C_CHAR字符类型来获取,后续使用数据的时候再转类型。代码如下:
int selectData(const string& sql,vector<string>& results)
{
CHAR csql[SQL_MAX_OPTION_STRING_LENGTH] = { 0 };
strcpy_s(csql, sql.c_str());
RETCODE ret = SQLExecDirect(hstmt1, (SQLCHAR*)csql, strlen(csql));
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
LLogError("select data error,error code:"<<ret);
return ret;
}
SQLCHAR midData[MAXCHAR] = { 0 };//注意这里:字符数组
SQLLEN midDataLength = 0;
SQLSMALLINT columnCount = 0;
SQLNumResultCols(hstmt1,&columnCount);
int line = 0;
while (SQLFetch(hstmt1) != SQL_NO_DATA_FOUND)
{
// 参数1为执行语句的句柄,
// 参数2为所要得到的数据位于的列数(SQL语句中),
// 参数3为数据类型,这个比较多,需要看一下MSDN
// 参数4为保存的位置(地址),
// 参数5为参数4可用的位置,既然参数3已设定为长整型,所以这里可使用0
// 参数6为实际返回的长度
stringstream ss;
++line;
ss << line;
for (int col = 1; col <= columnCount; ++col)
{
midData[0] = 0 ; //注意这里:重新赋空
ret = SQLGetData(hstmt1, col, SQL_C_CHAR, midData, MAXCHAR, &midDataLength);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
ss << "," << midData;
}
}
results.emplace_back(ss.str());//一个string就是表格的一行,用逗号分隔
}
SQLCancel(hstmt1); //注意,回到前一个状态,否则下次查询查不到哦
}
ODBC连接
SQLConnect的时候,使用的是odbc数据库源名称,在odbc数据源中设置。windows中安装了sql server manager后,相应的odbc应该也安装了,没有安装的话安装一个。然后配置一个odbc数据源(地址,账号,密码等),这里就是通过这个数据源名称选择连接那个数据源。
.
一个修改别人的整体的例子
这里只是测试验证,实际中我是封装了类的。否则就太乱了。
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <odbcss.h>
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc1 = SQL_NULL_HDBC;
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;
/*
cpp文件功能说明:
1.数据库操作中的添加,修改,删除,主要体现在SQL语句上
2.采用直接执行方式和参数预编译执行方式两种
*/
int main() {
RETCODE retcode;
UCHAR szDSN[SQL_MAX_DSN_LENGTH + 1] = "dataservice", //odbc数据库源名称,在odbc数据源中设置。windows中安装了sql server manager后,相应的odbc应该也安装了吧,没有安装的话安装一个。然后配置一个odbc数据源(地址,账号,密码等),这里就是通过这个数据源名称选择连接那个数据源。
szUID[MAXNAME] = "sa",
szAuthStr[MAXNAME] = "11";
//SQL语句
//直接SQL语句
UCHAR sql[74] = "SELECT * FROM[DataService].[dbo].[DailyFacts] where stockId = '600036.sh'";// "insert into test values('aaa','100')";
//预编译SQL语句
UCHAR pre_sql[29] = "insert into test values(?,?)";
//1.连接数据源
//1.环境句柄
retcode = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3,
SQL_IS_INTEGER);
//2.连接句柄
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
retcode = SQLConnect(hdbc1, szDSN, 12, szUID, 2, szAuthStr, 2);
UCHAR conInfo[125] = "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=sa;Initial Catalog=DataService;Data Source=10.101.223.13";
SQLCHAR* pwszConnStr=NULL;
//retcode = SQLDriverConnect(hdbc1,
// GetDesktopWindow(),
// pwszConnStr,
// SQL_NTS,
// NULL,
// 0,
// NULL,
// SQL_DRIVER_COMPLETE);
//判断连接是否成功
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) {
printf("连接失败!\n");
}
else {
//2.创建并执行一条或多条SQL语句
/*
1.分配一个语句句柄(statement handle)
2.创建SQL语句
3.执行语句
4.销毁语句
*/
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
//第一种方式
//直接执行
//添加操作
retcode=SQLExecDirect (hstmt1,sql,74);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
{
return 0;
}
SQLCHAR sqlnID[MAXCHAR] = {0};
SQLLEN sqlnIDLength = 0;
SQLCHAR columnName[MAXCHAR] = { 0 };
SQLSMALLINT DataType= 0;
SQLSMALLINT NameLength = 0;
SQLULEN columnsize = 0;
SQLSMALLINT dd = 0;
SQLSMALLINT na = 0;
SQLSMALLINT ddd = 0;
///* SQL data type codes */
//#define SQL_UNKNOWN_TYPE 0
//#define SQL_CHAR 1
//#define SQL_NUMERIC 2
//#define SQL_DECIMAL 3
//#define SQL_INTEGER 4
//#define SQL_SMALLINT 5
//#define SQL_FLOAT 6
//#define SQL_REAL 7
//#define SQL_DOUBLE 8
//#if (ODBCVER >= 0x0300)
//#define SQL_DATETIME 9
//#endif
//#define SQL_VARCHAR 12
//#if (ODBCVER >= 0x0300)
//#define SQL_TYPE_DATE 91
//#define SQL_TYPE_TIME 92
//#define SQL_TYPE_TIMESTAMP 93
//#endif
TIMESTAMP_STRUCT datetime;
while (SQLFetch(hstmt1) != SQL_NO_DATA_FOUND)
{
/* 获得数据 */
SQLGetData(hstmt1, 1, SQL_C_CHAR, sqlnID, MAXCHAR, &sqlnIDLength);
SQLDescribeCol(hstmt1, 3, columnName, 128, &NameLength, &DataType, &columnsize, &dd, &na);
SQLGetData(hstmt1, 5, SQL_C_SHORT, &ddd, sizeof(ddd), &sqlnIDLength);
SQLGetData(hstmt1, 3, SQL_C_TIMESTAMP, &datetime, sizeof(datetime), &sqlnIDLength);
// 参数1为执行语句的句柄,
// 参数2为所要得到的数据位于的列数(SQL语句中),
// 参数3为数据类型,这个比较多,需要看一下MSDN
// 参数4为保存的位置(地址),
// 参数5为参数4可用的位置,既然参数3已设定为长整型,所以这里可使用0
// 参数6为实际返回的长度
}
//第二种方式
//绑定参数方式
char a[200] = "bbb";
char b[200] = "200";
INT64 p = SQL_NTS;
//1预编译
//SQLPrepare(hstmt1, pre_sql, 29); //第三个参数与数组大小相同,而不是数据库列相同
2绑定参数值
//SQLBindParameter(hstmt1, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 200, 0, &a, 0, &p);
//SQLBindParameter(hstmt1, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 200, 0, &b, 0, &p);
3 执行
//SQLExecute(hstmt1);
printf("操作成功!");
//释放语句句柄
SQLCloseCursor(hstmt1);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
}
//3.断开数据源
/*
1.断开与数据源的连接.
2.释放连接句柄.
3.释放环境句柄 (如果不再需要在这个环境中作更多连接)
*/
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return(0);
}