【C语言】使用ODBC连接Microsoft SQL server数据库

时间:2022-06-28 20:36:55

因为最近要用C对SQL Server进行连接,但发现网上关于这方面的资料不多,就把这两天查到的资料和心得归拢了下,留着以后自己看。

使用C语言通过ODBC(开放式数据库互连)对SQL Server进行连接,分为两步操作:1.配置本地ODBC环境;2.码代码...=_=

【首先配置本地环境】
1.启动SQLSERVER服务,例如:HNHJ,开始菜单 ->运行 ->net start mssqlserver

【C语言】使用ODBC连接Microsoft SQL server数据库

2.更改SQL server登录方式为SQL Server身份验证登陆。

步骤:进入你的数据库->在服务器上右键->属性->安全性->SQL Server和Windows身份验证模式->点确定。

【C语言】使用ODBC连接Microsoft SQL server数据库

【C语言】使用ODBC连接Microsoft SQL server数据库

3.打开企业管理器,建立数据库,并在数据库中建立一张表。

我的数据库名字是CCCS,创建city表

【C语言】使用ODBC连接Microsoft SQL server数据库

4.建立系统DSN,开始菜单 ->运行 ->odbcad32

【C语言】使用ODBC连接Microsoft SQL server数据库

点击添加->SQL Server->数据源名称(自己起个名字记住,一会有用,我的是CCCS)->选择SQL Server服务器(选取本机名称,不要选local)->使用用户使用登录ID和密码的SQL Server验证->登录ID:sa,密码:(为空)->更改默认的数据库为:CCCS->测试数据源,测试成功,即DNS添加成功。

【C语言 关键函数】

1.SQLBindCol()函数具有六个参数,分别是

SQLRETURN SQLBindCol(
SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLINTEGER BufferLength,
SQLLEN * StrLen_or_Ind);

其中第一个参数是句柄,第二个参数是目标表中的列数(unsigned short),第三个是目标类型,第四个是储存数据库反馈信息(城市,纬度等)的字符串变量,第五个是第四个参数的长度(推荐使用strlen(string)测长度),第六个是啥玩意的缓冲区,为0即可。


2.SQLExecDirect()函数具有三个参数,分别是

SQLRETURN SQLExecDirect(
SQLHSTMT StatementHandle,
SQLCHAR * StatementText,
SQLINTEGER TextLength);


其中第一个参数是句柄,第二个参数是储存送给数据库的SQL语句的字符串变量,第三个函数是第二个参数的长度(推荐使用strlen(string)测长度)。


【源代码】

头文件functions.h附在主代码CCCS-insert.cpp和CCCS-select.cpp之后

【CCCS-insert.cpp】

#include "functions.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] = "CCCS"; //数据库名
UCHARszUID[MAXNAME] = "sa";//用户名
UCHARszAuthStr[MAXNAME] = ""; //密码
charsql[60] = "\0"; //插入时是用的sql语句的存放变量
charsqlh1[26] = "insert into city values('"; //拼合字符串
charsqlh2[4] = "','";
charsqlh3[3] = "')";
//UCHAR pre_sql[31] = "insert into city values(?,?,?)"; //预编译SQL语句
CityMsg * citymsg;//城市信息

//SQL语句
//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, 4, szUID, 2, szAuthStr, 0);

//判断连接是否成功
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);
//第一种方式
//直接执行
//添加操作

//打开文件
citymsg = getCityMsg();
citymsg = citymsg->next;
while(citymsg->next != NULL){
//拼合字符串
strcpy(sql,sqlh1);
strcat(sql,citymsg->city);
strcat(sql,sqlh2);
strcat(sql,citymsg->lat);
strcat(sql,sqlh2);
strcat(sql,citymsg->lon);
strcat(sql,sqlh3);
//执行sql语句
//SQLExecDirect (hstmt1,(UCHAR *)sql,50);
//测试
switch( SQLExecDirect (hstmt1,(UCHAR *)sql,strlen(sql))) {
case SQL_SUCCESS_WITH_INFO: {
printf("SQL_SUCCESS_WITH_INFO\n");
break;
}
case SQL_SUCCESS: {
printf("SQL_SUCCESS\n");
break;
}
case SQL_ERROR: {
printf("SQL_ERROR\n");
break;
}
default:
printf("else Return\n");

}
//测试结束
printf("%s\n",sql);//test
//重新初始化sql语句存放变量
strcpy(sql,sqlh1);
//链表指向下一节点
citymsg = citymsg->next;
}

//第二种方式
//绑定参数方式
/*char a[200]="bbb";
char b[200]="200";
char c[200]="200";
SQLINTEGER p = SQL_NTS;
//1预编译
SQLPrepare(hstmt1,pre_sql,31); //第三个参数与数组大小相同,而不是数据库列相同
//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);
SQLBindParameter(hstmt1,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,200,0,&c,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);
getchar();
return 0;
}


【CCCS-select.cpp】

/*
China City Coord System

SELECT
*/

#include "functions.h"

//定义查询方式宏
#defineSELECT_ALL0
#defineSELECT_CITYStill_Unsigned_Yet>_<|||
#defineSELECT_LAT_EXACT1
#defineSELECT_LAT_SCOPE2


SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc1 = SQL_NULL_HDBC;
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;

/******************************************************

全 部 查 询

*******************************************************/
void selectAll(
RETCODE retcode,
char * sql,
char * sqlh1,
char * initialize)

{
/*
1.确认一个结果集是否可用。
2.将结果集的列绑定在适当的变量上。
3.取得行
*/
CityMsg citymsg;

getchar();//储存在choose界面的回车字符,防止第一次翻页之前输出两倍的行数
strcpy(sql,sqlh1);//拼合sql语句字符串
SQLExecDirect (hstmt1,(UCHAR *)sql,strlen(sql));//对数据库发送select all语句
//SQLBindCol(hstmt1, 1, SQL_C_CHAR, list, 5, 0);//该函数对数据库发送语句
SQLBindCol(hstmt1, 1, SQL_C_CHAR, citymsg.city, 10, 0);//该函数是数据库的反馈信息函数
SQLBindCol(hstmt1, 2, SQL_C_CHAR, citymsg.lon, 11, 0);//第二个参数是目标表中的列号
SQLBindCol(hstmt1, 3, SQL_C_CHAR, citymsg.lat, 11, 0);//第五个参数是传回的字符串长度
do{
retcode = SQLFetch(hstmt1);
if(retcode == SQL_NO_DATA){
break;
}
printf("%s%s%s\n",citymsg.city, citymsg.lon, citymsg.lat);
static int n=1;//翻页计数器
n++;
if(n%20 == 0)//每页20行
{
printf("\n【第%d页】",n/20);//页码
getchar();//按回车换页
}
}while(1);
strcpy(sql,initialize);//重新初始化字符串

getchar();//结束标志,按一下回车
}


/******************************************************

纬 度 精 确 查 询

*******************************************************/
void selectByLat(
char * sqlh1,
char * sql,
char * initialize)
{

char sqlh5[10]="\0";
CityMsg citymsg;

getchar();
printf("输入要查询的纬度:\n");
printf("例如:34.17\n");
printf("北纬");
gets(sqlh5);

strcpy(sql,sqlh1);
strcat(sql,"where latitude='北纬");
strcat(sql,sqlh5);
strcat(sql,"'");

puts(sql);//显示向数据库发送的sql语句
SQLExecDirect (hstmt1,(UCHAR *)sql,strlen(sql));
SQLBindCol(hstmt1, 1, SQL_C_CHAR, citymsg.city, 10, 0);//该函数是数据库的反馈信息函数
SQLBindCol(hstmt1, 2, SQL_C_CHAR, citymsg.lon, 11, 0);//第二个参数是目标表中的列号
SQLBindCol(hstmt1, 3, SQL_C_CHAR, citymsg.lat, 11, 0);//第五个参数是传回的字符串长度
SQLFetch(hstmt1);
printf("%s%s%s\n",citymsg.city, citymsg.lon, citymsg.lat);
strcpy(sql,initialize);//重新初始化字符串

getchar();//结束标志,按一下回车
}

/*
查询SQLSERVER数据库,1.条件查询,2.直接查询全部
*/
int main(){
RETCODE retcode;
UCHAR szDSN[SQL_MAX_DSN_LENGTH+1] = "CCCS"; //数据库名
UCHARszUID[MAXNAME] = "sa";//用户名
UCHARszAuthStr[MAXNAME] = "";//密码
charsql[57] = "\0";//插入时是用的sql语句的存放变量
charinitialize[2] = "\0";//初始化变量
charsqlh1[20] = "select * from city ";//拼合字符串

retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3,
SQL_IS_INTEGER);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
//1.连接数据源
retcode = SQLConnect(hdbc1, szDSN, 4, szUID, 2, szAuthStr, 0);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("连接失败!");
} else {
//2.创建并执行一条或多条SQL语句
/*
1.分配一个语句句柄(statement handle)
2.创建SQL语句
3.执行语句
4.销毁语句
*/
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);

//第一种方式
/*
//直接执行
SQLExecDirect (hstmt1,(UCHAR *)sql,strlen(sql));
char list[5];
SQLBindCol(hstmt1, 1, SQL_C_CHAR, list, 5, 0);
SQLFetch(hstmt1);
printf("%s\n",list);*/

//第二种方式
/*
//绑定参数方式
char a[200]="aaa";
SQLINTEGER p = SQL_NTS;
//1.预编译
SQLPrepare(hstmt1,sql2,35); //第三个参数与数组大小相同,而不是数据库列相同
//2.绑定参数值
SQLBindParameter(hstmt1,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,200,0,&a,0,&p);
//3.执行
SQLExecute(hstmt1);
char list[5];
SQLBindCol(hstmt1, 1, SQL_C_CHAR, list, 5, 0);
SQLFetch(hstmt1);
printf("%s\n",list);
*/

int choose;//用户选择序号的储存变量

while(1){
printf("输入查询方式:\n");
printf("0.全部查询\n");
printf("1.纬度精确查询\n");
printf("2.纬度区间查询\n");
printf("\n");
scanf("%d",&choose);

switch(choose){
case SELECT_ALL:{
//全部输出
selectAll(retcode, sql, sqlh1, initialize);
break;
}
case SELECT_LAT_EXACT:{
//通过具体纬度查找
selectByLat(sqlh1,sql,initialize);
break;
}
case SELECT_LAT_SCOPE:{
//通过纬度区间查找


}
}
}

//释放语句句柄
SQLCloseCursor (hstmt1);
SQLFreeHandle (SQL_HANDLE_STMT, hstmt1);

}

//4.断开数据源
/*
1.断开与数据源的连接.
2.释放连接句柄.
3.释放环境句柄 (如果不再需要在这个环境中作更多连接)
*/
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
getchar();
getchar();
return(0);
}


 

【头文件functions.h】

#include <stdio.h>     
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <odbcss.h>

//存放城市及坐标的结构体
typedef struct CityMsg{
charcity[50];//城市city
charlon[50];//经度longitude
charlat[50];//纬度latitude
struct CityMsg*next;//下一节点
}CityMsg;

//函数声明
CityMsg * nextNood(CityMsg * );//构建链表 函数
CityMsg * getCityMsg();//获取城市及坐标 函数

//构建链表
CityMsg * nextNood(CityMsg * oldCM)
{
//尾插法
CityMsg * newCM;
newCM = (CityMsg *)malloc(sizeof(CityMsg));//为新节点开辟空间
newCM->next = NULL;//初始化新节点
oldCM->next = newCM;
return newCM;//返回新节点
}

//获取城市及坐标
CityMsg * getCityMsg()
{
CityMsg * head,//头指针
* citymsg;//存放城市及坐标的结构体
FILE *fp;//文件指针->存放城市及坐标的文件

head = (CityMsg *)malloc(sizeof(CityMsg));//为头指针开辟空间
citymsg = (CityMsg *)malloc(sizeof(CityMsg));//为首节点开辟空间
head->next = citymsg;//初始化头指针
citymsg->next = NULL;//初始化首节点

fp = fopen("CityCoord.txt","rt");//尝试打开文件
if(fp == NULL){//若打不开,反馈信息并退出
printf("Cannot Open This File,Press Any Key to Exit.\n");
getchar();
exit(1);
}
while(!feof(fp)){//循环读取城市及坐标信息,直到文件末尾
fscanf(fp,"%s %s %s",citymsg->city,citymsg->lon,citymsg->lat);//读入城市及坐标
citymsg = nextNood(citymsg);//开辟并指向下一节点
}
return head;
}


相关源码已上传git:Github.com/xusongqi/CCCS


【参考资料】

C语言与SQL SERVER数据库

如何更改SQL Server 2008 登陆验证方式

SQLExecDirect Function - SQL Server msdn