在嵌入式设备的开发中,sqlite数据库是非常常用的,虽然听着很高大上,但是实际开发难度不是很大,主要对它的函数要使用熟练。那么它到底是一个什么东西?
一. 数据库基本概念
数据库是在数据库管理系统管理和控制之下,存放在存储介质上的数据集合。
说的好难理解,其实就是个类似excel一样的东西,方便我们增删改查数据。
二. 常用的数据库
大型数据库
Oracle关系数据库(甲骨文产品的市场占有率高)。
IBM 的DB2(第一个具备网上功能的多媒体关系数据库管理系统,跨平台性强)
中型数据库
微软Server数据库(主要支持windows平台)
小型数据库
mySQL 开源关系数据库,但是对于嵌入式还是比较大
说了那么多,就是了解一下就完了,我们嵌入式中就是用SQLite
三. sqlite(轻量级的嵌入式数据库)
1. 特性
- 低内存占用率(全部源码大致3万行c代码,250KB)
- 跨平台可移植性
- 多语言支持
- 支持数据库大小至2TB;
- 免费开源
- 比目前流行的大多数数据库对数据的操作要快
这部分是夸自己呢,可以忽略,用它就对了!!
2.数据库的使用
上面说了半天,了解下就行了,这节才开始对这个东西的使用。那么这个东西怎么开始呢?
不急,先举个例子。
我们平时都玩电脑,假如你们老板让你统计一下你们公司所有同事的个人信息,姓名,身高啊,体重啊你该怎么做?
这很简单啊首先要在我们的电脑上下载个WPS软件(我是盗版没原装的),然后安装到我的电脑上,然后打开WPS,新建一个excel表格,然后按照姓名,身高,体重等信息填到表格中,依次将每个员工插入,当然也会有信息需要修改的情况,人家离职了你要删去的情况等(增删改查),其实我们的数据库的使用过程也是一样的。
说到这,你会说这么简单啊,我都会,不用再学了。
但是人家是轻量级的数据库,哪有什么图形界面让你操作,在我们的Linux下肯定要使用命令来进行操作啊,这多酷。
2.1Sqlite的安装(不明白,复习下linux包管理章节)
方法一:本地安装,官网下载安装包放到本地(db文件),然后解压安装sudo dpkg -i *.deb
方法二:在线安装(有网)sudo apt-get install sqlite3
有时还要装两个依赖库:sudo apt-get install libsqlite3-dev
sudo apt-get install sqlitebrowser
然后进入输入sqlite3,有打印信息输出,说明安装成功。
2.2 数据库的命令行操作
注:sqlite中的命令格式分为两种,
第一种系统命令 都以 '.' 开头。
此时打开进入sqlite软件,
1>退出,输入 .quit(或者 .exit)
2>查看sqlite支持哪些命令,输入 .help进行查看。
3>显示当前打开的数据库文件 .database
4>显示数据库中所有表名 .tables
5>查看表的结构 .schema
6>创建一个数据库 (库里面可以建很多表类似于建个文件夹,里面有很多excel表)
sqlite3 student.db //建了一个名为student的库
第二种是sql语句, 都以 ‘;’ 结尾。(sqlite3 数据库的增删改查)
1> 表格创建
create table stuinfo (id integer, name char, score float);
创建了一个名为stuinfo的表格,然后里面有编号,姓名,分数信息(对应表头)
这里面的数据类型,它做了一个对应
他的INTEGER 对应了我们的int.
REAL对应了我们的float
TEXT 对应char
2>向表格种插入数据记录。(增)
insert into stuinfo values(1001, 'zhangsan', 18, 80); //第一种插入形式
insert into stuinfo (id, name, score) values(1002, 'lisi', 90); //第二种形式
3>删除一条记录(删)
delete from stuinfo where id=1001 and name='zhangsan';
4>更新一条记录(改)
update stuinfo set name='wangwu', score = 82 where id=1002;
5>查看数据库记录
select * from stuinfo;
select * from stuinfo where score = 80;
select * from stuinfo where score = 80 and name= 'zhangsan';
select name,score from stuinfo; 查询指定的字段
select * from stuinfo where score >= 85 and score < 90;
6>增加一列
alter table stuinfo add column address char; //增加一列地址
7>删除一列
sqlite种没有删除列操作,如果想删除表A中的一列或者一行,首先通过SQL创建一个临时表,然后把表A中期望保留的数据存储到临时表中,然后把表A删除,再将临时表重命名为A.
create table stu as select id, name from stuinfo; //创建一个stu表将stuinfo中的姓名等信息保留到stu表中。
drop table stuinfo;//删除stuinfo表中的数据
alter table stu rename to stuinfo; //在将stu表重命名为stuinfo
8 >数据库表的维护(有了增删改查,其实我们在用excel的时候也注意到了ID自增等的一些操作)
比如我们在使用中ID啊都要求唯一,就需要输入一些关键字进行限定。
数据库主键(设置的数据将会是唯一的存在)
PRIMARY KEY
自增字段(设置的字段值自动递增)
AUTOONCREMENT
这个关键字只能用于整型(INTEGER)字段
2.3 数据库的编程API
上面我们说了一下在linux下的命令行操作数据库的一些指令,下面说一下它的编程API接口。
只说几个常用的,其他的可以查询sqlite 的API手册
1>打开数据库
函数名 | int sqlite3_open(const char *filename, sqlite3 **ppDb); | ||||
传入参数 |
| ||||
返回值 | 成功返回0,失败返回错误码(非零值) |
2>关闭数据库
函数名 | int sqlite3_close(sqlite3 *db);
| ||
传入参数 |
| ||
返回值 | 成功返回0,失败返回错误码 |
3>返回数据库错误信息
函数名 | const char *sqlite3_errmg(sqlite3 *db);
| ||
传入参数 |
| ||
返回值 | 返回错误信息 |
4>执行SQL语句操作(重点,且常用)
函数名 | int sqlite3_exec(sqlite3* db, const char *sql, int (*callback)(void* arg,int,char**,char**), void * arg, char **errmsg ); | ||||||||||
传入参数 |
| ||||||||||
返回值 | 成功返回0,失败返回错误码 |
查询回调函数(帮助在数据库中检索信息)
函数名 | int (*callback)(void* arg,int ncolumns ,char** f_value,char** f_name) | ||||||||
传入参数 |
| ||||||||
返回值 | 成功返回0 |
5>不使用回调函数执行SQL语句
函数名 | int sqlite3_get_table(sqlite3 *db, const char *sql, char ***resultp, int*nrow, int *ncolumn, char **errmsg);
| ||||||||||||
传入参数 |
| ||||||||||||
返回值 | 成功返回0,失败返回错误码 |
下面举个例子,就可以快速应用这些知识点了:
功能:假如我家开了个水果超市,有以下水果,想实现自动化管理,扫描二维码就能知道当前的水果状态,进货几天了,
好久需要再次进货,那些水果畅销,那些水果不畅销,那些水果春夏秋冬的价格波动,好,那么现在我想将
这些信息保存在数据库中,那么我应该怎么做;
提示: 建立一张fruit表,
假如水果有: 苹果,香蕉,梨,橘子,葡萄....(可以自己查一下英文保存到数据库)
水果价格: 苹果 5元/斤 香蕉 3元/斤 梨 3.5元/斤 橘子2.5元/斤 葡萄 8元/斤....
当前存货: 苹果 80斤 香蕉 200斤 梨 50斤 橘子300斤 葡萄 100斤....
超市每天水果都有进货和卖出嘛,水果的价格随着季节和天气也会有波动,顾客也会看一下每天水果的价格的嘛,
所以要求,根据上述提示,利用数据库完成水果店各种水果的增(进货)删(卖出)改(波动)查(看价格)功能。
并将进出货的时间和顾客光顾的时间记录到数据库中保存。
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
#define DATABASE "shop.db"
//增
void insert_data(sqlite3 *db)
{
char sql[128]={0};
char name_temp[32]={0};
char time_temp[32]={0};
float price_temp;
int stock_temp;
char *errmsg;
printf("请输入水果种类:");
scanf("%s", name_temp);
printf("请输入价格:");
scanf("%f", &price_temp);
printf("请输入进货数量:");
scanf("%d", &stock_temp);
printf("请输入进货时间:");
scanf("%s", time_temp);
sprintf(sql,"insert into fruit(name,price,stock,nowtime) values('%s',%f,%d,'%s');",name_temp,price_temp,stock_temp,time_temp);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){
printf("%s\n", errmsg);
}
else
{
printf("Insert success.\n");
}
}
//删
void delete_data(sqlite3 *db)
{
char sql[128]={0};
char name_temp[32]={0};
int stock_temp;
char *errmsg;
char time_temp[32]={0};
printf("请输入卖出的水果种类:");
scanf("%s", name_temp);
printf("请输入剩余的数量:");
scanf("%d", &stock_temp);
printf("请输入出货时间:");
scanf("%s", time_temp);
sprintf(sql,"update fruit set stock=%d,nowtime='%s' where name= '%s';",stock_temp,time_temp,name_temp);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){
printf("%s\n", errmsg);
}
else
{
printf("out success.\n");
}
}
//改
void updata_data(sqlite3 *db)
{
char sql[128]={0};
char name_temp[32]={0};
float stock_temp;
char *errmsg;
printf("请输入水果种类:");
scanf("%s", name_temp);
printf("请输入最新的价格:");
scanf("%f", &stock_temp);
printf("%s\n",name_temp);
sprintf(sql,"update fruit set price=%f where name= '%s';",stock_temp,name_temp);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){
printf("%s\n", errmsg);
}
else
{
printf("updata success.\n");
}
}
//查
int callback(void *arg, int f_num, char ** f_value, char ** f_name)
{
int i=0;
for(i=0;i< f_num;i++){
printf("%-13s ", f_value[i]);
}
putchar(10);
puts("-----------------------------------------------");
return 0;
}
void query_data(sqlite3 *db)
{
char name_temp[32]={0};
char sql[128] = {0};
char *errmsg;
sprintf(sql,"select * from fruit;");
if(sqlite3_exec(db,sql,callback,NULL,&errmsg) != SQLITE_OK){
printf("%s\n",errmsg);
}
}
int main(void)
{
int temp = 0;
sqlite3 *db;
char *errmsg;
//1.打开数据库
if(sqlite3_open(DATABASE, &db) != SQLITE_OK){
printf("%s",sqlite3_errmsg(db)); //打印出错信息
return -1;
}
//2.创建表 fruit.db
if(sqlite3_exec(db, "create table if not exists fruit(id integer primary key autoincrement, name text, price real ,stock integer,nowtime text);",NULL,NULL,&errmsg) != SQLITE_OK){
printf("%s\n",errmsg); //打印出错信息
return -1;
}
while(1){
//3.打印显示系统表头,提示用户输入相关操作
printf("****************************************************\n");
printf("**1:进货 2:出货 3.更新价格 4.价格查询 5.退出**\n");
printf("****************************************************\n");
printf("请输入操作值:");
scanf("%d", &temp);
switch(temp){
case 1:
insert_data(db);//进货
break;
case 2:
delete_data(db);//出货
break;
case 3:
updata_data(db);//更新价格
break;
case 4:
query_data(db);//价格查询
break;
case 5:
sqlite3_close(db);//退出
exit(0);
break;
default:
printf("请输入正确的选项\n");//提示用户重新输入
break;
}
}
return 0;
}
gcc -o sqlite sqlite_test.c -lsqlite3 进行编译
./sqlite进行执行
结果:
遇到的问题:
1.过程中,出现了,编译第一次没问题,编译第二次出现报错,提示重复创建了db文件,同时增加ID自增功能。
sqlite3_exec(db, "create table if not exists fruit(id integer primary key autoincrement, name text, price real ,stock integer);",NULL,NULL,&errmsg)、
2.在我们使用updata时也出现了问题。
sprintf(sql,"update fruit set stock= ‘%d‘, where name=‘%s’;",stock_temp,name_temp);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){
printf("%s\n", errmsg);
}
%d后面,多了个’ , ’号,%d不用加引号。
但是还是报错提示 no such column: ‘apple’,但是我的数据库中明明有这个字段啊。
但是我查询Id字段,还是库存字段都可以正常查询到。
问题记录:
通过命令行直接查看
但是为什么name这个字段不能查找成功??
name =’apple’要加一个引号,这些sql指令的规范一定要注意,很容易少引号,多逗号的,多练多熟悉才能更快的发现问题。