1. 程式人生 > >【資料庫】 sqlite3資料型別和函式

【資料庫】 sqlite3資料型別和函式

sqlite3支援的資料型別:

NULL、INTEGER、REAL、TEXT、BLOB
但是,sqlite3也支援如下的資料型別
smallint           16位整數
integer             32位整數
decimal(p,s)   p是精確值,s是小數位數
float                  32位實數
double             64位實數
char(n)             n長度字串,不能超過254
varchar(n)        長度不固定最大字串長度為n,n不超過4000
graphic(n)        和 char(n) 一樣,但是單位是兩個字元double-bytes,n不超過127(中文字)
vargraphic(n)  可變長度且最大長度為n

date                  包含了年份、月份、日期
time                  包含了小時、分鐘、秒
timestamp       包含了年、月、日、時、分、秒、千分之一秒

sqlite3支援的函式

【1】日期函式

datetime() : 產生日期和時間
date(): 產生日期
time():產生時間
strftime():對以上3個函式產生的日期和時間進行格式化

用法例項:
1、SELECT date('2011-9-9','+1 day','+1 year'); 結果是 2010-09-10
2、SELECT datetime('now'); 當前日期和時間
3、SELECT datetime('now', 'start of month'); 本月的第一天零點,也可以設定年和日的第一天
4、SELECT datetime('now','+1 hour','-12 minute'); 當前時間加48分鐘

strftime()函式可以將YYYY-MM-DD HH:MM:SS格式的日期字串轉換為其它形式的字串

%d:天數,01-31
%f :小數形式的秒,SS.SSS
%H:小時
%j  :某一天是該年的第幾天,001-366
%m:月份,00-12
%M:分鐘,00-59
%s:從1970到現在的秒數
%S:秒,00-59
%w:星期,0-6,0是星期天
%W:某天是該年的第幾周,01-53
%Y:年,YYYY
%% 百分號

應用舉例:
SELECT strftime('%Y.%m.%d %H:%M:%S','now','localtime');


二、【算術函式】

abs(X):返回絕對值
max(X,Y[,...]):返回最大值
min(X,Y,[,...]):返回最小值
random(*):返回隨機數
round(X[,Y]): 四捨五入

三、【字串處理函式】


length(x) :返回字串字元個數
lower(x) :大寫轉小寫
upper(x):小寫轉大寫
substr(x,y,Z):擷取子串
like(A,B):確定給定的字串與指定的模式是否匹配

四、【條件判斷函式、集合函式、其它函式】

typeof(x):返回資料的型別
last_insert_rowid():返回最後插入的資料的ID

********************************************************************************************************************

sqlite3提供了C函式介面來操作sqlite3資料庫,其中有個關鍵資料結構 sqlite3 * 型別

1、開啟資料庫
int sqlite3_open(檔名,sqlite3 **);  - 檔名若不存在,則會自動建立
返回SQLITE_OK表示操作正常,這些巨集的定義在sqlite3.h檔案中定義,看原始碼會懂的更多

2、關閉資料庫
int sqlite3_close(sqlite3 *);

3、SQL語句操作
int sqlite3_exec(sqlite3 *,const char *sql, sqlite3_callback,void *,char **errmsg);
這就是執行一條sql語句的函式
引數1:open函式得到的指標
引數2:一條sql語句,以'\0'結尾
引數3:sqlite3_callback是回撥,當這條語句執行後,sqlite3會呼叫你提供的這個函式,回撥函式要查閱資料
引數4:void *是自己提供的指標,可以傳遞任何指標到這裡,這個引數最終會傳到回撥函式裡面,如果不需要
傳到回撥函式裡面,則可以設定為NULL
引數5:錯誤資訊,當執行失敗時,可以查閱這個指標,可以利用printf("%s\n",errmsg)得到一串字串資訊,
該資訊表明出錯的地方

通常,sqlite3_callback和void *都設定為NULL,表示不需要回調,比如做insert、delete操作,就沒有必要使用回撥,而當使用select時,就要使用回撥,因為sqlite3把資料查出來,得通過回撥來說明查出什麼資料


回撥函式的定義格式:
typedef int (*sqlite3_callback)(void *,int,char **,char **);

例項如下:

//sqlite 每查到一條記錄,就呼叫一次這個回撥
int LoadMyInfo(void *para,int n_column,char **column_value,char **column_name)
{
	/*para: 在sqlite3裡傳入的void *引數,通過該引數可以傳入一些特殊指標
	 *如類指標、結構指標,然後在這裡轉換成對應的型別(這裡是void *型別),
	 *必須強制轉換成自己的型別才可用,然後操作這些資料*/
	 
	//n_column: 該記錄有多少個欄位(列)
	
	/*char **column_value 儲存著查出來的資料,實際上是個1維陣列,每一個元素都是
	 *char *值,是一個欄位內容(用字串表示,以\0結尾)*/
	 
	//char **column_name 與 column_value 是對應的,表示這個欄位的欄位名稱
	
	//這裡不是用para引數
	
	printf("%=記錄包含%d\n個欄位",n_column);
	
	for(i=0;i<n_column;i++)
	{
		printf("欄位名: %s ,欄位值:%s\n",column_name[i],column_value[i]);
	}
	
	printf("\n");
	
	return 0;
}

int main(int , char **)
{
	sqlite3 *db;
	int result;
	char *errmsg = NULL;
	char sql[512];
	
	result = sqlite3_open("My.db",&db);
	if(result != SQLITE_OK)
	{
		//資料庫開啟失敗
		return -1; 
	}
	
	//建立資料表
	strcpy(sql,"CREATE TABLE test(ID INTEGER PRIMARY KEY,NAME VARCHAR(32));");
	result = sqlite3_exec(db,sql,NULL,NULL,errmsg);
	if(result != SQLITE_OK)
	{
		printf("建立表失敗,錯誤:%s\n",errmsg);
	}
	
	//插入記錄
	strcpy(sql,"INSERT INTO test VALUES(1,'OK');");
	result = sqlite3_exec(db,sql,0,0,errmsg);
	if(result != SQLITE_OK)
	{
		printf("插入記錄失敗,錯誤:%s\n",errmsg);
	}
	
	//查詢資料庫
	strcpy(sql,"SELECT * FROM test;");
	result = sqlite3_exec(db,sql,LoadMyInfo,NULL,errmsg);
	
	sqlite3_close(db);
	
	return 0;
}


以上是通過回撥查詢資料庫,如果該函式在C++中,就要將其宣告成static型別,因為C++
成員函式隱藏了一個引數:this,C++呼叫類的成員函式的時候,隱含把類指標當函式的第
一個引數傳遞進去,就與上面的sqlite回撥函式引數不符

除了使用回撥來查詢,還可以使用非回撥的查詢,通過sqlite3_get_table函式做到
int sqlite3_get_table(sqlite3*,const char *sql,char ***resultp,int *nrow,int *ncolumn,char **errmsg);
引數3:resultp 是一維陣列,第一行是欄位名稱,跟著是每個欄位的值
引數4:查詢共多少條記錄
引數5:查詢共多少個欄位

操作例項如下:

int main(int ,char **)
{
	sqlite3 *db;
	int result;
	char *errmsg = NULL;
	
	char **dbResult;
	int nRow,nColumn;
	int i,j;
	int index;
	
	char sql[512];
	
	result = sqlite3_open("My.db",&db);
	if(result != SQLITE_OK)
	{
		return -1;
	}
	
	result = sqlite3_get_table(db,sql,&dbResult,&nRow,&nColumn,&errmsg);
	//查詢成功
	if(SQLITE_OK == result) 
	{
		//dbResult第一行是欄位名稱,從nColumn索引開始時真正的資料
		index = nColumn;
		printf("查詢到%d記錄\n",nRow);
		
		for(i=0;i<nRow;i++)
		{
			for(j=0;j<nColumn;j++)
			{
				printf("欄位名稱:%s,欄位值:%s\n",dbResult[j],dbResult[index]);
				index++;
			}
			printf("\n");
		}
	}
	
	//釋放char**查詢結果
	sqlite3_free_table(dbResult); 
	
	sqlite3_close(db);
	
	return 0;
}


上述使用的方法適用於大多數資料庫需求,但是不能適用於二進位制資料,操作二進位制資料方法需要用到一個數據型別sqlite3_stmt *,該資料型別記錄了一個"sql語句",這裡的sql語句是解析後的,用sqlite自己標記記錄的內部資料結構,並不是我們熟悉的sql語句

資料插入到 sqlite3_stmt結構裡可不能直接memcpy,也不能像std::string那樣用+號,必須用sqlite提供的
函式來插入。

假設有建立一張表如下
CREATE TABLE test2(ID INTEGER,file_content BLOB)

首先宣告 sqlite3_stmt *stat; 然後將一個sql語句解析到stat結構裡去
sqlite3_prepare(db,"INSERT INTO test2(ID,file_content) VALUES(10,?)",-1,&stat,0);
這裡sql語句中有個?號,在該函式裡,?表示一個未定的值
引數3:表示前面sql語句的長度,如果小於0,sqlite會自動計算它的長度
引數4:sqlite3_stat指標的指標,解析後的sql語句就放在該結構裡
引數5:一般設為0

返回值為SQLITE_OK且stat不為NULL,表示成功,當prepare成功後,開始查詢資料
int result = sqlite3_step(stat);
該值返回SQLITE_ROW 表示成功

可以迴圈執行sqlite3_step函式,一次step查詢出一條記錄,直到返回值不為SQLITE_ROW
然後開始獲取第一個欄位:ID值,ID是個整數,使用如下操作
int id = sqlite3_column_int(stat,0); //0表示第1欄位
下面獲取file_content的值,因為file_content是二進位制,因此需要得到它的指標,還有長度
const void * pFileContent = sqlite3_column_blob(stat,1);
int len = sqlite3_column_bytes(stat,1);
把 pFileContent內容儲存後,要釋放sqlite3_stmt結構
sqlite3_finalize(stat);

如果需要重複使用 sqlite3_prepare解析好的sqlite3_stmt結構,使用 sqlite3_reset函式
result = sqlite3_reset(stat);
這樣,stat結構又成為sqlite3_prepare完成時的狀態

sqlite 資料庫事務處理

如果需要同步刪除很多資料,可以將它們做成一個統一的事務,通常sqlite3_exec就是一次事務,假設要刪除1W條記錄,sqlite就做了1W次,開始事務->刪除資料->提交事務,這個操作很慢,我們可以將同類操作作成一個事物,如果操作錯誤,還可以回滾事務

事務的操作沒有特別的介面函式,只是普通的sql語句
int result;
result = sqlite3_exec(db,"begin transtraction",0,0,&zErrorMsg);
result = sqlite3_exec(db,"commit transtraction",0,0,&zErrorMsg);
result = sqlite3_exec(db,"rollback transtraction",0,0,&zErrorMsg);

 sqlite3 錯誤編碼如下:

#define SQLITE_OK           0   /* Successful result */
#define SQLITE_ERROR        1   /* SQL error or missing database */
#define SQLITE_INTERNAL     2   /* An internal logic error in SQLite */
#define SQLITE_PERM         3   /* Access permission denied */
#define SQLITE_ABORT        4   /* Callback routine requested an abort */
#define SQLITE_BUSY         5   /* The database file is locked */
#define SQLITE_LOCKED       6   /* A table in the database is locked */
#define SQLITE_NOMEM        7   /* A malloc() failed */
#define SQLITE_READONLY     8   /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite_interrupt() */
#define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT     11   /* The database disk image is malformed */
#define SQLITE_NOTFOUND    12   /* (Internal Only) Table or record not found */
#define SQLITE_FULL        13   /* Insertion failed because database is full */
#define SQLITE_CANTOPEN    14   /* Unable to open the database file */
#define SQLITE_PROTOCOL    15   /* Database lock protocol error */
#define SQLITE_EMPTY       16   /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA      17   /* The database schema changed */
#define SQLITE_TOOBIG      18   /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT  19   /* Abort due to contraint violation */
#define SQLITE_MISMATCH    20   /* Data type mismatch */
#define SQLITE_MISUSE      21   /* Library used incorrectly */
#define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
#define SQLITE_AUTH        23   /* Authorization denied */
#define SQLITE_ROW         100  /* sqlite_step() has another row ready */
#define SQLITE_DONE        101  /* sqlite_step() has finished executing */