1. 程式人生 > >C/C++使用ODBC連線Microsoft SQL server資料庫

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),第三個是目標型別,第四個是儲存資料庫反饋資訊(城市,緯度等)的字串變數,第五個是第四個引數的長度

(推薦使用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";     <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;
}