因為最近要用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),第三個是目標類型,第四個是儲存資料庫反饋資訊(城市,緯度等)的字串變數,第五個是第四個參數的長度(推薦使用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 SystemSELECT*/#include "functions.h"//定義查詢方式宏#defineSELECT_ALL0#defineSELECT_CITYStill_Unsigned_Yet>_<|||#defineSELECT_LAT_EXACT1#defineSELECT_LAT_SCOPE2SQLHENV 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];//城市citycharlon[50];//經度longitudecharlat[50];//緯度latitudestruct 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;}
【參考資料】
C語言與SQL SERVER資料庫
如何更改SQL Server 2008 登陸驗證方式
SQLExecDirect Function - SQL Server msdn