1 - 什么是SQlite
- SQLite是一款輕型的嵌入式數(shù)據(jù)庫(kù)
- SQLite數(shù)據(jù)庫(kù):可以存儲(chǔ)大批量的數(shù)據(jù)
- 它占用資源非常的低,在嵌入式設(shè)備中,可能只需要幾百K的內(nèi)存就夠了
- 它的處理速度比Mysql、PostgreSQL這兩款著名的數(shù)據(jù)庫(kù)都還快
- 數(shù)據(jù)庫(kù)(Database)是按照數(shù)據(jù)結(jié)構(gòu)來組織、存儲(chǔ)和管理數(shù)據(jù)的倉(cāng)庫(kù).
1.1 - 數(shù)據(jù)庫(kù)可以分為2大種類:
- 關(guān)系型數(shù)據(jù)庫(kù)(主流)
- 對(duì)象型數(shù)據(jù)庫(kù)
- 常用關(guān)系型數(shù)據(jù)庫(kù)
- PC端:Oracle、MySQL、SQL Server、Access、DB2、Sybase
- 嵌入式\移動(dòng)客戶端:SQLite
2 - 如何存儲(chǔ)數(shù)據(jù)
- 數(shù)據(jù)庫(kù)的存儲(chǔ)結(jié)構(gòu)和excel很像,以表(table)為單位來存儲(chǔ)數(shù)據(jù)
2.1 - 數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)的步驟
- 新建一個(gè)數(shù)據(jù)庫(kù)文件
- 新建一張表(table)
- 添加多個(gè)字段(column,列,屬性)
- 添加多行記錄(row,每行存放多個(gè)字段對(duì)應(yīng)的值)
3 - SQL語(yǔ)句 (DDL DML DQL)
演示圖片所用的軟件為綠色版的Navicat.
3.1 - SQL語(yǔ)句的種類
- 3.1.1 - 數(shù)據(jù)定義語(yǔ)句(DDL:Data Definition Language)
- 包括
create(創(chuàng)表)
和drop(刪表)
等操作 - 在數(shù)據(jù)庫(kù)中創(chuàng)建新表或刪除表(
create table
或drop table
) - 3.1.2 - 數(shù)據(jù)操作語(yǔ)句(DML:Data Manipulation Language)
- 包括
insert
、update
、delete
等操作 - 上面的3種操作分別用于添加、修改、刪除表中的數(shù)據(jù)
- 3.1.3 - 數(shù)據(jù)查詢語(yǔ)句(DQL:Data Query Language)
- 可以用于查詢獲得表中的數(shù)據(jù)
- 關(guān)鍵字
select
是DQL(也是所有SQL)用得最多的操作 - 其他DQL常用的關(guān)鍵字有
where
,order by
,group by
和having
3.1.1 - DDL(數(shù)據(jù)定義語(yǔ)句)
創(chuàng)表格式
- create table 表名 (字段名1 字段類型1, 字段名2 字段類型2, …) ;
- create table if not exists 表名 (字段名1 字段類型1, 字段名2 字段類型2, …) ;
create table t_student (id integer, name text, age inetger, score real) ;
字段類型
SQLite將數(shù)據(jù)劃分為以下幾種存儲(chǔ)類型:
integer : 整型值
real : 浮點(diǎn)值
text : 文本字符串
blob : 二進(jìn)制數(shù)據(jù)(比如文件)
實(shí)際上SQLite是無類型的
就算聲明為integer類型,還是能存儲(chǔ)字符串文本(主鍵除外)
建表時(shí)聲明啥類型或者不聲明類型都可以,也就意味著創(chuàng)表語(yǔ)句可以這么寫:
create table t_student(name, age);
-
為了保持良好的編程規(guī)范、方便程序員之間的交流,編寫建表語(yǔ)句的時(shí)候最好加上每個(gè)字段的具體類型
由于以上創(chuàng)表后是沒有主鍵和自生長(zhǎng)的 所以創(chuàng)建表最好的方式是:
-
在創(chuàng)表的時(shí)候附帶主鍵和自生長(zhǎng)
刪表格式
- drop table 表名 ;
- drop table if exists 表名 ;
drop table t_student ;
3.1.2 - DML(數(shù)據(jù)操作語(yǔ)句)
- 插入數(shù)據(jù)(insert
- insert into 表名 (字段1, 字段2, …) values (字段1的值, 字段2的值, …) ;
示例
insert into t_student (name, age) values (jack’, 10) ;
- 注意
- 數(shù)據(jù)庫(kù)中的字符串內(nèi)容應(yīng)該用單引號(hào) ’ 括住;
- 更新數(shù)據(jù)(update)
update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值, … ;
update t_student set name = ‘jack’, age = 20 ;
- 注意
- 上面的示例會(huì)將t_student表中所有記錄的name都改為jack,age都改為20
- 刪除數(shù)據(jù)(delete)
delete from 表名 ;
delete from t_student ;
- 注意
- 上面的示例會(huì)將t_student表中所有記錄都刪掉
3.1.3 - DQL (條件語(yǔ)句)
- 如果只想更新或者刪除某些固定的記錄,那就必須在DML語(yǔ)句后加上一些條件
- 條件語(yǔ)句的常見格式
where 字段 = 某個(gè)值 ; // 不能用兩個(gè) =
where 字段 is 某個(gè)值 ; // is 相當(dāng)于 =
where 字段 != 某個(gè)值 ;
where 字段 is not 某個(gè)值 ; // is not 相當(dāng)于 !=
where 字段 > 某個(gè)值 ;
where 字段1 = 某個(gè)值 and 字段2 > 某個(gè)值 ; // and相當(dāng)于C語(yǔ)言中的 &&
where 字段1 = 某個(gè)值 or 字段2 = 某個(gè)值 ; // or 相當(dāng)于C語(yǔ)言中的 ||
// 將t_student表中年齡大于10 并且 姓名不等于jack的記錄,年齡都改為 5
update t_student set age = 5 where age > 10 and name != ‘jack’ ;
// 刪除t_student表中年齡小于等于10 或者 年齡大于30的記錄
delete from t_student where age <= 10 or age > 30 ;
// 將t_student表中名字等于jack的記錄,score字段的值 都改為 age字段的值
update t_student set score = age where name = ‘jack’ ;
- 查詢數(shù)據(jù)
select 字段1, 字段2, … from 表名 ;
select * from 表名; // 查詢所有的字段
select name, age from t_student ;
select * from t_student ;
select * from t_student where age > 10 ; // 條件查詢
- 起別名(字段和表都可以起別名)
select 字段1 別名 , 字段2 別名 , … from 表名 別名 ;
select 字段1 別名, 字段2 as 別名, … from 表名 as 別名 ;
select 別名.字段1, 別名.字段2, … from 表名 別名 ;
// 給name起個(gè)叫做myname的別名,給age起個(gè)叫做myage的別名
select name myname, age myage from t_student ;
// 給t_student表起個(gè)別名叫做s,利用s來引用表中的字段
select s.name, s.age from t_student s ;
- 計(jì)算記錄的數(shù)量
select count (字段) from 表名 ;
select count ( * ) from 表名 ;
select count (age) from t_student ;
select count ( * ) from t_student where score >= 60
- 排序
- 查詢出來的結(jié)果可以用order by進(jìn)行排序
select * from t_student order by 字段 ;
select * from t_student order by age ;
- 默認(rèn)是按照升序排序(由小到大),也可以變?yōu)榻敌颍ㄓ纱蟮叫。?/li>
select * from t_student order by age desc ; //降序
select * from t_student order by age asc ; // 升序(默認(rèn))
- 也可以用多個(gè)字段進(jìn)行排序
// 先按照年齡排序(升序),年齡相等就按照身高排序(降序)
select * from t_student order by age asc, height desc ;
- 分頁(yè) - limit常用來做分頁(yè)查詢,比如每頁(yè)固定顯示5條數(shù)據(jù),那么應(yīng)該這樣取數(shù)據(jù)
第1頁(yè):limit 0, 5
第2頁(yè):limit 5, 5
第3頁(yè):limit 10, 5
第n頁(yè):limit 5*(n-1), 5
- 猜猜下面語(yǔ)句的作用
select * from t_student limit 7 ;
相當(dāng)于select * from t_student limit 0, 7 ;
表示取最前面的7條記錄
主鍵和約束
- 簡(jiǎn)單約束
- 建表時(shí)可以給特定的字段設(shè)置一些約束條件,常見的約束有
- not null :規(guī)定字段的值不能為null
- unique :規(guī)定字段的值必須唯一
- default :指定字段的默認(rèn)值
(建議:盡量給字段設(shè)定嚴(yán)格的約束,以保證數(shù)據(jù)的規(guī)范性)
create table t_student (id integer, name text not null unique, age integer not null default 1) ;
name字段不能為null,并且唯一
age字段不能為null,并且默認(rèn)為1
主鍵約束
- 如果t_student表中就name和age兩個(gè)字段,而且有些記錄的name和age字段的值都一樣時(shí),那么就沒法區(qū)分這些數(shù)據(jù),造成數(shù)據(jù)庫(kù)的記錄不唯一,這樣就不方便管理數(shù)據(jù)
- 良好的數(shù)據(jù)庫(kù)編程規(guī)范應(yīng)該要保證每條記錄的唯一性,為此,增加了主鍵約束
- 也就是說,每張表都必須有一個(gè)主鍵,用來標(biāo)識(shí)記錄的唯一性
什么是主鍵
- 主鍵(Primary Key,簡(jiǎn)稱PK)用來唯一地標(biāo)識(shí)某一條記錄
- 例如
t_student
可以增加一個(gè)id字段作為主鍵,相當(dāng)于人的身份證 - 主鍵可以是一個(gè)字段或多個(gè)字段
主鍵的設(shè)計(jì)原則
- 主鍵應(yīng)當(dāng)是對(duì)用戶沒有意義的
- 永遠(yuǎn)也不要更新主鍵
- 主鍵不應(yīng)包含動(dòng)態(tài)變化的數(shù)據(jù)
- 主鍵應(yīng)當(dāng)由計(jì)算機(jī)自動(dòng)生成
主鍵的聲明
- 在創(chuàng)表的時(shí)候用primary key聲明一個(gè)主鍵
create table t_student (id integer primary key, name text, age integer) ;
pinteger類型的id作為t_student表的主鍵
主鍵字段
只要聲明為primary key,就說明是一個(gè)主鍵字段
主鍵字段默認(rèn)就包含了not null 和 unique 兩個(gè)約束
如果想要讓主鍵自動(dòng)增長(zhǎng)(必須是integer類型),應(yīng)該增加
autoincrement
create table t_student (id integer primary key autoincrement, name text, age integer) ;
外鍵約束
- 利用外鍵約束可以用來建立表與表之間的聯(lián)系
- 外鍵的一般情況是:一張表的某個(gè)字段,引用著另一張表的主鍵字段
新建一個(gè)外鍵
create table t_student (id integer primary key autoincrement, name text, age integer, class_id integer, constraint fk_t_student_class_id_t_class_id foreign key (class_id) (id)) ; references t_class
- t_student表中有一個(gè)叫做fk_t_student_class_id_t_class_id的外鍵
- 這個(gè)外鍵的作用是用t_student表中的class_id字段引用t_class表的id字段
表鏈接
什么是表連接查詢
- 需要聯(lián)合多張表才能查到想要的數(shù)據(jù)
表連接的類型
內(nèi)連接:inner join 或者 join (顯示的是左右表都有完整字段值的記錄)
左外連接:left outer join (保證左表數(shù)據(jù)的完整性)
查詢1020班的所有學(xué)生
select s.name,s.age from t_student s, t_class c where s.class_id = c.id and c.name = ‘1020’;
FMDB
- FMDB是iOS平臺(tái)的SQLite數(shù)據(jù)庫(kù)框架
- FMDB以O(shè)C的方式封裝了SQLite的C語(yǔ)言API
- 使用起來更加面向?qū)ο螅∪チ撕芏嗦闊⑷哂嗟腃語(yǔ)言代碼
- 對(duì)比蘋果自帶的Core Data框架,更加輕量級(jí)和靈活
- 提供了多線程安全的數(shù)據(jù)庫(kù)操作方法,有效地防止數(shù)據(jù)混亂
FMDB有三個(gè)主要的核心類
1 - FMDatabase
- 一個(gè)FMDatabase對(duì)象就代表一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫(kù)
- 用來執(zhí)行SQL語(yǔ)句
2 - FMResultSet
- 使用FMDatabase執(zhí)行查詢后的結(jié)果集
3 - FMDatabaseQueue
- 用于在多線程中執(zhí)行多個(gè)查詢或更新,它是線程安全的
打開數(shù)據(jù)庫(kù)
- 通過指定SQLite數(shù)據(jù)庫(kù)文件路徑來創(chuàng)建FMDatabase對(duì)象
FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
NSLog(@"數(shù)據(jù)庫(kù)打開失敗!");
}
文件路徑有三種情況
- 1 - 具體文件路徑
- 如果不存在會(huì)自動(dòng)創(chuàng)建
- 2 - 空字符串@""
- 會(huì)在臨時(shí)目錄創(chuàng)建一個(gè)空的數(shù)據(jù)庫(kù)
- 當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫(kù)文件也被刪除
- 3 - nil
- 會(huì)創(chuàng)建一個(gè)內(nèi)存中臨時(shí)數(shù)據(jù)庫(kù),當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)庫(kù)會(huì)被銷毀
執(zhí)行更新
- 在FMDB中,除查詢以外的所有操作,都稱為“更新”
- create、drop、insert、update、delete等
使用executeUpdate:方法執(zhí)行更新
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"];
執(zhí)行查詢
- 查詢方法
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
// 查詢數(shù)據(jù)
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];
// 遍歷結(jié)果集
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
double score = [rs doubleForColumn:@"score"];
}
FMDatabaseQueue
- FMDatabase這個(gè)類是線程不安全的,如果在多個(gè)線程中同時(shí)使用一個(gè)FMDatabase實(shí)例,會(huì)造成數(shù)據(jù)混亂等問題
- 為了保證線程安全,F(xiàn)MDB提供方便快捷的FMDatabaseQueue類
FMDatabaseQueue的創(chuàng)建
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
簡(jiǎn)單使用
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
使用事務(wù)
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Rose"];
[db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jim"];
FMResultSet *rs = [db executeQuery:@"select * from t_student"];
while ([rs next]) {
// …
}
}];
事務(wù)回滾
*rollback = YES;