C/C++使用ODBC連線Microsoft SQL server資料庫
因為最近要用C對SQL Server進行連線,但發現網上關於這方面的資料不多,就把這兩天查到的資料和心得歸攏了下,留著以後自己看。
使用C語言通過ODBC(開放式資料庫互連)對SQL Server進行連線,分為兩步操作:1.配置本地ODBC環境;2.碼程式碼...=_=
【首先配置本地環境】
1.啟動SQLSERVER服務,例如:HNHJ,開始選單 ->執行 ->net start mssqlserver
2.更改SQL server登入方式為SQL Server身份驗證登陸。
步驟:進入你的資料庫->在伺服器上右鍵->屬性->安全性->SQL Server和Windows身份驗證模式->點確定。
3.開啟企業管理器,建立資料庫,並在資料庫中建立一張表。
我的資料庫名字是CCCS,建立city表
4.建立系統DSN,開始選單 ->執行 ->odbcad32
點選新增->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),第三個是目標型別,第四個是儲存資料庫反饋資訊(城市,緯度等)的字串變數,第五個是第四個引數的長度
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"; <span style="margin: 0px; padding: 0px; border: 0px; background: transparent;"> </span>//資料庫名
UCHAR szUID[MAXNAME] = "sa"; //使用者名稱
UCHAR szAuthStr[MAXNAME] = ""; <span style="margin: 0px; padding: 0px; border: 0px; background: transparent;"> </span>//密碼
char sql[60] = "\0"; <span style="margin: 0px; padding: 0px; border: 0px; background: transparent;"> </span>//插入時是用的sql語句的存放變數
char sqlh1[26] = "insert into city values('"; <span style="margin: 0px; padding: 0px; border: 0px; background: transparent;"> </span>//拼合字串
char sqlh2[4] = "','";
char sqlh3[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"
//定義查詢方式巨集
#define SELECT_ALL 0
#define SELECT_CITY Still_Unsigned_Yet>_<|||
#define SELECT_LAT_EXACT 1
#define SELECT_LAT_SCOPE 2
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"; //資料庫名
UCHAR szUID[MAXNAME] = "sa"; //使用者名稱
UCHAR szAuthStr[MAXNAME] = ""; //密碼
char sql[57] = "\0"; //插入時是用的sql語句的存放變數
char initialize[2] = "\0"; //初始化變數
char sqlh1[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{
char city[50]; //城市 city
char lon[50]; //經度 longitude
char lat[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;
}