微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sqlite3的简单使用

实验代码

#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <string.h>
//sqlite3的回调函数  sqlite 每查到一条记录,就调用一次这个回调 
//              传递的私有参数  一行有多少字段       字段值                  字段名
int LoadMyInfo( void * para,int n_column,char ** column_value,char ** column_name ) 
{ 
//para是你在 sqlite3_exec 里传入的 void * 参数 
//通过para参数,你可以传入一些特殊的指针(比如类指针、结构指针),然后在这里面强制转换成对应的类型
//(这里面是void*类型,必须强制转换成你的类型才可用)。然后操作这些数据 
//n_column是这一条记录有多少个字段 (即这条记录有多少列) 
// char ** column_value 是个关键值,查出来的数据都保存在这里,它实际上是个1维数组(不要以为是2维数组),
//每一个元素都是一个 char * 值,是一个字段内容(用字符串来表示,以\0结尾) 
//char ** column_name 跟 column_value是对应的,表示这个字段的字段名称 

	int i; 

	printf("This is %d column\n",n_column ); 
	for( i = 0 ; i < n_column; i ++ ) 
	{ 
		printf( "column name is :%s  --->column value is :%s\n",column_name[i],column_value[i] ); 
		if(para != NULL)//当传递的指针不为空的时候,拷贝信息
			strcpy((char *)para,column_value[i]);
	} 
	printf( "------------------\n"); 
	return 0; 
} 
int main( int argc,char **argv ) 
{ 
	sqlite3 * db; 
	int result; 
	char * errmsg = NULL; 
	char  msg[50];
	char ** dbResult;
	int nRow=0,nColumn=0;
	int i,j;
	//int sqlite3_open( 文件名,sqlite3 ** );
	result = sqlite3_open("exec2.db",&db ); 
	if( result != sqlITE_OK ) 
	{ 
		//数据库打开失败 
		return -1; 
	} 

	//数据库操作代码 
	//创建一个测试表,表名叫 MyTable_1,有2个字段: ID 和 name。其中ID是一个自动增加的类型,以后insert时可以不去指定这个字段,它会自己从0开始增加 
	result = sqlite3_exec( db,"create table MyTable(ID integer primary key autoincrement,name nvarchar(32))",NULL,&errmsg ); 
	if(result != sqlITE_OK ) 
	{ 
		printf("create table Failed  The error number is %d,Error message is %s\n ",result,errmsg ); 
	} 

	//插入一些记录 
	result = sqlite3_exec( db," insert into MyTable( name ) values (' on foot ')",&errmsg ); 
	if(result != sqlITE_OK ) 
	{ 
		printf("Insert infor Failed  The error number is %d,errmsg ); 
	} 
	result = sqlite3_exec( db," insert into MyTable( name ) values (' by bike ')",&errmsg ); 
	if(result != sqlITE_OK ) 
	{ 
		printf("Insert infor  Failed  The error number is %d," insert into MyTable( name ) values (' by car ')",errmsg ); 
	} 
	
//int sqlite3_exec(sqlite3*,const char *sql,sqlite3_callback,void *,char **errmsg );
	//开始查询数据库,有多少条数据将会被回调多少次
	result = sqlite3_exec( db," select * from MyTable ",LoadMyInfo,&errmsg ); 
	//通过回调函数进行查询并且返回,查询值
	result = sqlite3_exec( db,"select * from MyTable where ID=2",msg,&errmsg);
	printf("The value of ID=2 is %s\n",msg);

	result=sqlite3_get_table(db,"select * from MyTable",&dbResult,&nRow,&nColumn,&errmsg);
	if( errmsg != NULL){
		sqlite3_free_table(dbResult);
		errmsg = NULL;
	}
	for(i=0;i<nRow;i++)
	{
		for(j=0;j<nColumn;j++)
		{
			printf( " %s   ",*(dbResult + i*nColumn +j));
		}
		printf("\n");
	}
	sqlite3_free_table(dbResult);
	//关闭数据库 
	sqlite3_close( db ); 
	return 0; 
}

实验结果:
[root@localhost sqlite3]# ./exec
This is 2 column
column name is :ID  --->column value is :1
column name is :name  --->column value is : on foot 
------------------
This is 2 column
column name is :ID  --->column value is :2
column name is :name  --->column value is : by bike 
------------------
This is 2 column
column name is :ID  --->column value is :3
column name is :name  --->column value is : by car 
------------------
This is 2 column
column name is :ID  --->column value is :2
column name is :name  --->column value is : by bike 
------------------
The value of ID=2 is  by bike 
 ID    name   
 1     on foot    
 2     by bike    


sqlITE_API int sqlite3_exec(
sqlite3 *db,/* The database on which the sql executes */
const char *zsql,/* The sql to be executed */
sqlite3_callback xCallback,/* Invoke this callback routine */
void *pArg,/* First argument to xCallback() */
char **pzErrMsg /* Write error messages here */
){
int rc = sqlITE_OK;
const char *zLeftover;
sqlite3_stmt *pStmt = 0;
char **azCols = 0;

int nRetry = 0;
int nCallback;

/* 查询语句是空的 */
if( zsql==0 ) zsql = "";

/* 线程安全:加锁保护 */
sqlite3_mutex_enter(db->mutex);
/* 设置错误为OK */
sqlite3Error(db,sqlITE_OK,0);
while( (rc==sqlITE_OK 
|| (rc==sqlITE_SCHEMA && (++nRetry)<2)) && zsql[0] ){ /*当返回sqlITE_SCHEMA时需要重新prepare,重新操作数据库;并且是仅重复1次,而且查询语句是存在的 */

/* 在 sqlite 版本3中,当一个预处理 sql 语句不合法不能执行时就会返回一个 sqlITE_SCHEMA 错误。当这个错误发生时,该语句应当用 sqlite3_prepare() API函数重新编译。在 sqlite 版本3中,只有使用 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API函数执行 sql 才会发生这个错误,而使用 sqlite3_exec(). 则不会。这与版本2不同。

大部分发生这个错误的原因是当 sql 预处理完时数据库已经改变了(可能是被另一个进程改变的)。还可能有如下原因:

对一个数据库进行DETACH操作 
对一个数据库进行VACUUM操作 
一个用户函数定义被删除或改变了。 
一个排序定义被删除或改变了。 
一个授权函数改变了。*/

int nCol;
char **azVals = 0;

pStmt = 0;

/* prepare compile sql : 这里通过设置nByte可以加速操作,这里用了-1*/
rc = sqlite3_prepare(db,zsql,-1,&pStmt,&zLeftover);
assert( rc==sqlITE_OK || pStmt==0 );
if( rc!=sqlITE_OK ){
continue;
}
if( !pStmt ){
/* 前导语句错误 . 这是在语句前有注释或者空格的条件下会发生 */
zsql = zLeftover;
continue;
}

nCallback = 0;

/* 查询列数 */
nCol = sqlite3_column_count(pStmt);

while( 1 ){
int i;

/* 查询数据 : 如果是插入数据等更新操作,会返回sqlITE_DONE ;如果是检索数据,会返回sqlITE_ROW */
/* 一次一行,相当于移动光标 */
rc = sqlite3_step(pStmt);

/* 如果存在回调函数,并且是检索类数据时调用回调 */
if( xCallback && (sqlITE_ROW==rc ||
(sqlITE_DONE==rc && !nCallback && db->flags&sqlITE_NullCallback)) ){
if( 0==nCallback ){
/* 首次执行call back,分配列数据空间 */
if( azCols==0 ){
azCols = sqlite3DbMallocZero(db,2*nCol*sizeof(const char*) + 1);
if( azCols==0 ){
goto exec_out;
}
}

/* 获取名称 */
for(i=0; i<nCol; i++){
azCols[i] = (char *)sqlite3_column_name(pStmt,i);
/* sqlite3VdbeSetColName() installs column names as UTF8
** strings so there is no way for sqlite3_column_name() to fail. */
assert( azCols[i]!=0 );
}

/* 回调变为1,改变了状态,下次不再调用,及仅需要执行一次列的信息提取工作*/
nCallback++;
}
if( rc==sqlITE_ROW ){
/* 计算查询的列数据:这里使用了c新标准--执行期间申请数组 */
azVals = &azCols[nCol];
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt,i);
if( !azVals[i] && sqlite3_column_type(pStmt,i)!=sqlITE_NULL ){
db->mallocFailed = 1;
goto exec_out;
}
}
}

/* 执行回调函数:注意回调函数在正确的条件下要返回0,发生错误返回非0值;我一般错误条件下都是返回-1 */
if( xCallback(pArg,nCol,azVals,azCols) ){
rc = sqlITE_ABORT;
sqlite3_finalize(pStmt);
pStmt = 0;
sqlite3Error(db,sqlITE_ABORT,0);
goto exec_out;
}
}

if( rc!=sqlITE_ROW ){

/* 查询后处理:删除prepare object */
rc = sqlite3_finalize(pStmt);
pStmt = 0;
if( rc!=sqlITE_SCHEMA ){
nRetry = 0;
zsql = zLeftover;

/* 去掉sql 空格前导字符 */
while( isspace((unsigned char)zsql[0]) ) zsql++;
}
break;
}

/* 执行下一次查询处理 */
}

/* 释放列信息空间 */
sqlite3DbFree(db,azCols);
azCols = 0;
}

exec_out:

/* 回收清除工作 */
if( pStmt ) sqlite3_finalize(pStmt);
sqlite3DbFree(db,azCols);

rc = sqlite3ApiExit(db,rc);
if( rc!=sqlITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
*pzErrMsg = sqlite3Malloc(nErrMsg);
if( *pzErrMsg ){
memcpy(*pzErrMsg,sqlite3_errmsg(db),nErrMsg);
}
}else if( pzErrMsg ){
*pzErrMsg = 0;
}

assert( (rc&db->errMask)==rc );
sqlite3_mutex_leave(db->mutex);
return rc;
}


sqlite3 *db创建数据库类型的指针,通过sqlite3_open()函数使db指针指向该数据库

注意:

1、char **dbResult;字符型的二重指针,将数据库sqlite3_get_table()出来的数据以字符的方式给dbResult。

2、select * from age;查询student数据库里的age表全部内容

3、my_age = atoi(dbResult[nColumn]);将查询出来给dbResult的数据(字符)通过aoti()转换成整型交给变量my_age供程序中直接应用。

重点:(假设age表里有n个字段)

1、通过select * from age;给dbResult的字符前n个(0,n)为字段名称(只有计算机认识),dbResult[n]以后分别代表字段的值(包括dbResult[n])。如图

* * * * .........* (dbResult[0]~[n-1]分别代表字段名)

dbResult[n] [n+1] [n+2] [n+3].....[n+n-1] (dbResult[n]~[n+n-1]分别代表第一条记录的值)

dbResult[2n][2n+1][2n+2][2n+3]....[2n+n-1](dbResult[2n]~[2n+n-1]分别代表第二条记录的值)

dbResult[3n][3n+1][3n+2]32n+3]....[3n+n-1](dbResult[3n]~[3n+n-1]分别代表第三条记录的值)

注:sqlite3_get_table()之后便将以上的n(字段数:简称列)给了nColumn这个变量,可直接应用。nRow变量代表共有多少条记录,可直接应用。

2、通过select * from age where id=0;如果查到0条记录的话nRow等于0,查到1条记录的话nRow等于1,假设查到1条数据,举例:

* * * * .........* (dbResult[0]~[n-1]分别代表字段名)

dbResult[n] [n+1] [n+2] [n+3].....[n+n-1] (dbResult[n]~[n+n-1]分别代表第一条记录的值)

注:此时dbResult[]只有0~2n-1共2n个字符,此时如果对dbResult[2n]引用的话就会出错。查询两条语句的话以此类推。

* * * * .........* (dbResult[0]~[n-1]分别代表字段名)

dbResult[n] [n+1] [n+2] [n+3].....[n+n-1] (dbResult[n]~[n+n-1]分别代表第一条记录的值)

dbResult[2n][2n+1][2n+2][2n+3]....[2n+n-1](dbResult[2n]~[2n+n-1]分别代表第二条记录的值)

注:此时dbResult[]只有0~3n-1可引用。

原文地址:https://www.jb51.cc/sqlite/202141.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐