SQLite及FMDB简介
常用关键字:
select、insert、update、delete、from、create、where、desc、order、by、group、table、alter、view、index等;数据库中不可以使用关键字来命名表、字段。
SQLite数据库存储的数据形式:
- NULL:表示该值为NULL值
- INTEGER:无符号整型值
- REAL:浮点值
- TEXT:文本字符串
- BLOB:二进制数据(比如文件)
注意:实际上SQLite是无类型的,就算声明为integer类型,还是能存储字符串文本,声明类型是为了方便程序员之间的交流。
- DDL(Data Definition Language)数据定义语言
语句包括动词CREATE(创建表)、DROP(删除表) - DML(Data Manipulation Language)数据操作语言
语句包括INSERT(插入行)、UPDATE(修改行)、DELETE(删除行) - DQL(Data Query Language)数据查询语句
语句包括SELECT,查询数据
DDL语句
- 创建表:
CREATE TABLE 表明(字段名1 字段类型1,字段名2 字段类型2,…);
CREATE TABLE if not exists 表明(字段名1 字段类型1,字段名2 字段类型2,…);
示例:
create table t_person(id integer, name text, age integer);
create table if not exists t_person(id integer, name text, age integer);
- 删表:
drop table 表名;
示例:
drop table t_person;
- 简单约束:
建表的时候可以给特定的字段设置一些约束条件
1.用 not null 指定字段的值不能为null
2.用 unique 指定字段的值必须唯一
3.用 default 指定字段的默认值
示例:
CREATE TABLE t_student(id integer, name text NOT NULL UNIQUE, age integer NOT NULL DEFAULT 1);
以上语句约束表示:
1.name字段不能为NULL,并且唯一
2.age字段不能为NULL,并且默认为1
DML语句
- 插入数据(insert)
insert into 表名(字段1,字段2,…)values(字段1的值,字段2的值,...);
eg:
insert into t_person(name, age) values(“jack”, 10);
注意:数据库中的字符串内容应该用引号括住
- 更新数据(update)
update 表名 set 字段1=字段1的值,字段2=字段2的值,…;
eg:
update t_person set name = ‘jack’, age = 20;
这条语句会将t_person表中所有记录的name都改为jack,age都改为20
- 删除数据(delete)
delete from 表名;
eg:
delete from t_person;
这条语句会将t_person 表中所有记录都删掉
引入:通过上面例子发现,以上语句会更新\删除表中所有记录,如果我们只想更新或删除某些固定的记录,那就必须在DML语句后加上一些条件,即条件语句。
- 条件语句
格式:
1.where 字段=某个值 and 字段 > 某个值;// and相当于&&
2.where 字段=某个值 or 字段=某个值;// or相当于 ||
举例:
//1.将年龄大于10且姓名不等于jack的记录年龄改为5:
update t_person set age = 5 where age > 10 and name != ‘jack’;
//2.删除年龄小于等于10或者年龄大于30的记录:
delete from t_person where age <= 10 or age >30;
DQL语句
即查询语句,格式如下:
- 查询格式:
select 字段1,字段2,...from 表名;
select name,age from t_person; - 如果想查询所有的字段可以用:
select * from 表名;
select * from t_person; - 也可以添加条件语句
select * from t_person where age > 20; - 计算记录的数量可以用count(字段) 或者 count()
select count() from t_person;
select count(age) from t_person where height < 1.80;
查询排序
- 语法
select * from t_person order by 字段; - 示例
select * from t_person order by age desc; // 降序
select * from t_person order by age asc; // 升序(默认,asc可不写)
限制查询数量
- 语法:select * from 表名 limit 数值1,数值2;
- 示例:select * from t_person limit 4, 8; // 跳过最前面4条语句,然后取8条记录。
limit语句可以被用于强制SELECT语句返回指定的记录数,LIMIT接收一个或两个数字参数,参数必须是一个整数常量,如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目,初始记录行的偏移量是0而不是1。
主键约束(pk)
当t_person有些记录的name属性和age属性都一样时,那么就无法区分这些数据,造成数据库的记录不唯一,不方便管理数据;为了保证每条记录的唯一性,增加了主键约束;主键是用来唯一地标识某一条记录的,可以是一个字段或多个字段,比如t_person可以增加一个id字段作为主键,相当于身份证号,主键必须具有唯一性。
主键设计原则:
- 主键应当是对用户没有意义的
- 永远不要更新主键
- 主键不应该包含动态变化的数据
- 主键应当由计算机自动生成
在创建表的时候用 primary key 声明一个主键,只要声明为 primary key,就说明是一个主键字段,主键字段默认包含了 not null 和 unique 两个约束。
eg:
CREATE TABLE t_student (id integer PRIMARY KEY, name text, age integer);
如果想让主键自动增长(integer),应该增加AUTOINCREMENT
eg:
CREATE TABLE t_student (id integer PRIMARY KEY AUTOINCREMENT, name text, age integer);
外键约束(FK)
外键约束可以用来建立表与表之间的联系(例如每个班级都有不同的老师,老师群体又有自己的数据库,所以要建立班级表与老师表之间的联系)
- 新建一个外键:
CREATE TABLE class (class_id integer PRIMARY KEY AUTOINCREMENT, teacher_id integer REFERENCES teacher(id));
- JOIN和ON用来建立两个表之间的关联关系:
SELECT s.name, s.age FROM t_movie s JOIN t_director b ON s.dir_id = b.id WHERE s.name = ‘Matrix';
数据库操作流程:
(3.0版本SQLite,使用前需要导入libsqlite3.0.dylib)
- 打开数据库
- 编译SQL语句
- 执行SQL语句
- 语句完结
- 关闭数据库
SQLite3.0使用的是C的函数接口,常用函数有:
sqlite3_open() //打开数据库
sqlite3_close() //关闭数据库
sqlite3_exec() //执行SQL语句,例如创建表
sqlite3_prepare_v2() //编译SQL语句
sqlite3_step() //执行查询SQL语句
sqlite3_finalize() //结束SQL语句
sqlite3_bind_text() //绑定参数
sqlite3_column_text() //查询字段上的数据
简单使用数据库示例代码:
#import "ViewController.h"
#import <sqlite3.h>
@interface ViewController ()
@end
sqlite3 *_sql;
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
/*
0. 导入依赖库并导入<sqlite3.h>头文件
1. 需要一个数据库文件
2. 在数据库文件中创建一个表格
3. 向表格中插入数据
4. 关闭数据库
*/
#pragma mark - 1.打开数据库/创建数据库文件并打开数据库
NSString *filePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/mySql.db"];
NSLog(@"%@",filePath);
//sqlite3_open 打开数据库 但是如果路径下没有数据库文件的话会先创建一个数据库文件,再执行打开的操作
int isOpen = sqlite3_open([filePath UTF8String], &_sql);
NSLog(@"%d",isOpen);
if (isOpen == SQLITE_OK) {
NSLog(@"打开数据库成功");
}else {
return;
}
#pragma mark - 2.创建表格
NSString *createSQL = @" create table t_class (id integer primary key autoincrement, className text, teacher text); ";
char *error = nil;
/*
1. 打开的一个数据库对象
2. 需要执行的sql语句
*/
int isOK = sqlite3_exec(_sql, [createSQL UTF8String], NULL, NULL, &error);
if (isOK == SQLITE_OK) {
NSLog(@"创建表格成功");
}
#pragma mark - 3.添加数据
NSString *insertSQL = @" insert into t_class (className,teacher) values (\"class01\",\"tank\"); ";
int insertOK = sqlite3_exec(_sql, [insertSQL UTF8String], NULL, NULL, &error);
if (insertOK == SQLITE_OK) {
NSLog(@"添加数据成功");
}
#pragma mark - 4.数据查询
NSString *selectSQL = @"select * from t_class where id = ?; ";
// SQL语句的句柄
sqlite3_stmt *stmt = nil;
/* 替代SQL语句
1. 向句柄中插入数据(需要在SQL语句中设置占位符,占位符在句柄中的位置从1开始)
2. 从句柄中获取数据(当数据查询时使用,查询后获取的字段信息在句柄中的位置从0开始)
*/
/*
参数3:查询数据的字节限制 设置为-1 则不对查询结果做任何的设置
参数4:一个SQL语句的句柄 用来作为查询结果的存放集合
*/
//sqlite3_prepare_v2 编译SQL语句,判断SQL语句是否合法,并将SQL语句和句柄相互绑定
int prepare = sqlite3_prepare_v2(_sql, [selectSQL UTF8String], -1, &stmt, NULL);
if (prepare == SQLITE_OK) {
NSLog(@"语句合法");
sqlite3_bind_int(stmt, 1, 1);
// 执行句柄 开始查询语句
int step = sqlite3_step(stmt);
_models = [[NSMutableArrayalloc] init];
while (step == SQLITE_ROW) {
// 说明还有一条数据待查询
int c_id = sqlite3_column_int(stmt, 0);
constunsignedchar *className = sqlite3_column_text(stmt, 1);
constunsignedchar *teacher = sqlite3_column_text(stmt, 2);
ClassModel *model = [[ClassModelalloc] init];
model.c_id = c_id;
model.className = [NSStringstringWithUTF8String:className];
model.teacher = [NSStringstringWithUTF8String:teacher];
[_modelsaddObject:model];
}
}
NSLog(@"%@",_models);
#pragma mark - 5.关闭数据库
sqlite3_close_v2(_sql);
}
FMDB的使用
FMDB是iOS平台的SQLite数据库框架,以OC的方式封装了SQLite的C语言API。
FMDB使用起来更加面向对象,省去了相对冗余的C语言代码;而相对于苹果自带的Core Data框架,FMDB更加轻量级;FMDB还提供了多线程安全的数据库操作方法,有效地防止数据混乱。
FMDB主要有三个类:
1.FMDatabase:一个FMDatabase对象就代表一个单独的SQLite数据库,执行SQL语句。
2.FMResultSet:使用FMDatabase执行查询后的结果集。
3.FMDatabaseQueue:用于在多线程中执行多个查询或更新(它是线程安全的)
FMDB简单使用代码示例:
/*
1. 创建一个数据库文件
2. 创建表格
*/
NSString *filePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/sql.db"];
FMDatabase *db = [FMDatabasedatabaseWithPath:filePath];
NSLog(@"%@",filePath);
BOOL isOpen = [db open];// 打开数据库文件如果没有数据库则创建之后再打开
if (!isOpen) {
NSLog(@"打开失败");
return;
}
// 创建表格
NSString *createSQL = @" CREATE TABLE IF NOT EXISTS t_student (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL); ";
BOOL createSuc = [db executeUpdate:createSQL];
if (createSuc) {
NSLog(@"创建表格成功");
}
// 添加数据
for (int i = 10; i < 20; i ++) {
NSString *name = [NSStringstringWithFormat:@"tank%d号",i+1];
BOOL insertSuc = [db executeUpdateWithFormat:@"insert into t_student(name, age) values (%@,%d)",name,20];
if (insertSuc) {
NSLog(@"添加数据成功");
}
}
// 删除数据
BOOL deleteSuc = [db executeUpdate:@" delete from t_student where id > 10; "];
if (deleteSuc) {
NSLog(@"删除数据成功");
}
// 刷新数据
BOOL updataSuc = [db executeUpdate:@" update t_student set name = \"carol\" where id < 10; "];
if (updataSuc) {
NSLog(@"刷新数据成功");
}
// 数据查询
FMResultSet *set = [db executeQuery:@" select * from t_student; "];
// 循环遍历所有的查询结果
while ([set next]) {
NSString *name = [set stringForColumn:@"name"];
int age = [set intForColumn:@"age"];
NSLog(@"%@ %d",name, age);
}
//关闭数据库
[db close];