說明
本文是作者Lefe所創(chuàng),轉(zhuǎn)載請注明出處,如果你在閱讀的時候發(fā)現(xiàn)問題歡迎一起討論。本文會不斷更新。
正文
對于iOS應(yīng)用,我相信有很多人還選擇使用sqlite作為數(shù)據(jù)的持久化操作,但是對于一個還沒有接觸過sqlite的同學(xué)難免會有點不知所措,我記得我曾經(jīng)剛接觸sqlite的時候,花費了不少時間。那是的我不知道如何連變查詢,如何創(chuàng)建表,如何使用聚合函數(shù)等等。下面這篇文章希望能幫助你少走一些彎路。
一、數(shù)據(jù)類型:
如果你在創(chuàng)建表的時候,需要指定某個字段的數(shù)據(jù)類型,下面是一些基本的數(shù)據(jù)類型,當然這里我沒有一一列出,只列出了常用的一些。
- text:文本是字符數(shù)據(jù) // ’3.14’
- integer:整形,比如枚舉值 // 314
- real: 實數(shù)的十進制數(shù)值 // 3.14
- boolean:布爾型
- varchar:字符型
- NULL:表示沒有值 // NULL
二、終端使用技巧:
當你學(xué)習(xí)使用sqlite的時候,直接在終端輸入(這里以mac為例):sqlite3 database_name,按回車鍵,比如:<code>sqlite3 wsy.db</code>,不過在使用的過程中有一些技巧幫你更好的查看數(shù)據(jù),比如找到創(chuàng)建的所有表,創(chuàng)建表所使用的SQL語句,顯示表中的數(shù)據(jù)的時候連同列名一塊顯示,等等。
.header on
查詢時將顯示列名;
.mode column
顯示模式為列顯示模式
.width 20
調(diào)整列寬
.timer on
顯示運行某個SQL花費的時間
.schema teacher
teacher表創(chuàng)建的SQL語句,前提是你需要創(chuàng)建一張teacher表
.tables
顯示所有的表
.show
顯示所有配置信息
.help
查看更多技巧
注意:如果不執(zhí)行.header on
,執(zhí)行.mode column
和.width 20
將不會起作用
三、創(chuàng)建數(shù)據(jù)表:
會使用終端創(chuàng)建數(shù)據(jù)庫后,你可以直接創(chuàng)建表,當然這里只是為了演示,在真正的開發(fā)過程中,可以使用sqlite自己分裝一系列操作數(shù)據(jù)的方法。如果為了省時省力,可以直接使用FMDB。根據(jù)實際情況,創(chuàng)建表的時候需要注意哪些字段是主鍵,哪些字段需要添加約束,表之間如何關(guān)聯(lián)。
為表添加約束:
創(chuàng)建數(shù)據(jù)庫表的時候可以為表添加約束,這樣可以避免非法數(shù)據(jù)插入到數(shù)據(jù)庫中
-NOT NULL
: 確保一列不能有NULL值;
-DEFAULT
: 提供一列的默認值;
-UNIQUE
: 確保某一列所有值不同(唯一);
-PRIMARY KEY
: 主鍵,唯一標識數(shù)據(jù)庫表中的各行記錄;
-CHECK
: CHECK約束,確保一列中的所有值滿足一定條件。
1.創(chuàng)建teacher表,主鍵( PRIMARY KEY)為id
CREATE TABLE IF NOT EXISTS teacher(id VARCHAR(20) PRIMARY KEY, name TEXT, age INT, sex INT);
2.創(chuàng)建teacher表,主鍵( PRIMARY KEY)為id,且不能為null,name不能為null,age必須大于0,sex默認的是0
CREATE TABLE IF NOT EXISTS teacher(id VARCHAR(20) PRIMARY KEY NOT NULL, name TEXT NOT NULL, age INT CHECK(age>0), sex INT DEFAULT 0);
3.創(chuàng)建teacher表,主鍵( PRIMARY KEY)為(id, name),復(fù)合主鍵,創(chuàng)建表的時候可以使用復(fù)合主鍵,保證復(fù)合主鍵中的一列唯一即可,比如(1,wsy),(2,wsy),(1,ws)都是合法的值
CREATE TABLE IF NOT EXISTS teacher(id VARCHAR(20) NOT NULL,name TEXT NOT NULL, age INT, sex INT DEFAULT 0, PRIMARY KEY(id, name));
例子:
- 打開終端(以mac為例),輸入:sqlite3 wsy.db,點擊回車
- 輸入創(chuàng)建表的sql語句,記得一定要加分號:
CREATE TABLE IF NOT EXISTS teacher(id VARCHAR(20), name TEXT NOT NULL, age INT CHECK(age>0), sex INT DEFAULT 0, PRIMARY KEY(id, name));
- 向teacher表中插入數(shù)據(jù):
sqlite>INSERT INTO teacher(id, name, age, sex) VALUES (1234, 'wsy', 25, 1);
sqlite>INSERT INTO teacher(id, name, age, sex) VALUES (1234, 'wsy', 25, 1);
主鍵約束,不能插入一樣的數(shù)據(jù)
Error: UNIQUE constraint failed: teacher.id, teacher.name
CHECK約束,年齡必須大于0
sqlite> INSERT INTO teacher(id, name, age, sex) VALUES (1235, 'wsy', -10, 1);
Error: CHECK constraint failed: teacher
默認值:sex沒有插入,默認值為0,由于復(fù)合主鍵的原因,(1235, 'wsy', 20)可以插入
sqlite> INSERT INTO teacher(id, name, age) VALUES (1235, 'wsy', 20);
sqlite> SELECT *FROM teacher;
id | name | age | sex
1235 | wsy | 20 | 0
NOT NULL約束:name不能為空
sqlite> INSERT INTO teacher(id, age) VALUES (1235, 20);
Error: NOT NULL constraint failed: teacher.name
最后數(shù)據(jù)庫中的表中的數(shù)據(jù)如下 id name age sex
1234 wangsuyan 25 1
1234 wsy 25 1
1235 wsy 20 0
Run Time: real 0.000 user 0.000158 sys 0.000087
四、插入數(shù)據(jù)
建好表以后就可以想表中插入數(shù)據(jù),當然可以一次性插入一行或者多行數(shù)據(jù)。
格式:
INSERT INTO table_name(column_list) VALUES (value_list);
向某個表中插入數(shù)據(jù),column_list是以逗號分割的字段名稱,value_list是用逗號分割的值,這些值必須與column_list中的一一對應(yīng)。
向teacher表中插入一條記錄:
INSERT INTO teacher(id, name, age, sex) VALUES (1234, 'wangsuyan', 25, 1);
插入數(shù)據(jù)的時候也可以省略字段名稱(列名),字段名稱必須和值一一對應(yīng)
INSERT INTO teacher VALUES (1236, 'wsy', 25, 1);
可以一次性插入多條記錄:
CREATE TABLE IF NOT EXISTS temp_teacher (userId TEXT PRIMARY KEY, age INT);
DISTINCT 是為了去重,userId是主鍵,如果在插入數(shù)據(jù)中遇到約束錯誤,那么所有的數(shù)據(jù)將插入失敗
INSERT INTO temp_teacher SELECT DISTINCT id, age FROM teacher;
userId age
1234 25
1235 20
1236 25
插入某一列中的某條數(shù)據(jù)
INSERT INTO temp_teacher VALUES(1237, (SELECT age FROM teacher WHERE id=1237));
五、查詢數(shù)據(jù)
數(shù)據(jù)查詢在數(shù)據(jù)庫操作中起到了很大的作用,巧妙的使用SQL語句會減少很多的數(shù)據(jù)處理操作。SELECT命令用一系列子句將很多關(guān)系操作組合到一起,每個子句代表一種特定的關(guān)系操作。
格式:
SELECT [DISTINCT] HEADING
FROM tables
WHERE predicate
GROUP BY columns
HAVING predicate
ORDER BY columns
LIMIN count,offset
常用的SELECT語句:
1、查詢表中所有數(shù)據(jù):
sqlite> SELECT *FROM teacher;
id name age sex
1234 wangsuyan 25 1
1234 wsy 25 1
1235 wsy 20 0
1236 wsy 25 1
1237 wangsuyan 25 1
1238 good 25 1
1238 hello 25 1
1239 hello 26 1
Run Time: real 0.000 user 0.000175 sys 0.000089
2、按條件查詢
sqlite> SELECT *FROM teacher WHERE id=1234 AND name=‘wsy’;
id name age sex
1234 wsy 25 1
3、去重,去掉重復(fù)的字段,注意以下語句的不同
SELECT DISTINCT *FROM teacher;
SELECT DISTINCT id, name FROM teacher;
sqlite> SELECT DISTINCT name FROM teacher;
name
wangsuyan
wsy
good
hello
4、聚合函數(shù)的使用
<1>查詢數(shù)據(jù)行數(shù)
sqlite> SELECT COUNT() FROM teacher;
COUNT()
8
<2>查詢數(shù)據(jù)行數(shù),起一個別名為count
sqlite> SELECT COUNT(*) AS count FROM teacher;
count
8
<3>最大值,最大年齡
sqlite> select MAX(age) FROM teacher;
MAX(age)
26
<4>最小值,最小年齡
sqlite> SELECT MIN(age) as minAge FROM teacher;
minAge
20
<5>平均年齡
sqlite> SELECT AVG(age) FROM teacher;
AVG(age)
24.5
<6>求和
sqlite> SELECT SUM(age) FROM teacher;
SUM(age)
196
<7>絕對值
sqlite> SELECT ABS(5), ABS(-15), ABS(NULL), ABS(0), ABS(“ABC");
ABS(5) ABS(-15) ABS(NULL) ABS(0) ABS('ABC')
5 15 0 0.0
<8>大寫,小寫,長度
sqlite> SELECT UPPER(name), LOWER(name), LENGTH(name) FROM teacher;
UPPER(name) LOWER(name) LENGTH(name)
WANGSUYAN wangsuyan 9
WSY wsy 3
WSY wsy 3
WSY wsy 3
WANGSUYAN wangsuyan 9
GOOD good 4
HELLO hello 5
HELLO hello 5
5、查詢最后插入的行:
sqlite> SELECT last_insert_rowid();
6、模糊查詢
LIKE:模糊查詢,_表示一個,%表示多個或一個
例如:查詢第二個字母為“s”的姓名
sqlite> SELECT *FROM teacher WHERE name LIKE '_s%';
id name age sex
1234 wsy 25 1
1235 wsy 20 0
1236 wsy 25 1
7、排序,查詢teacher表中所有數(shù)據(jù),并且按age降序排列,默認為升序排列
sqlite> SELECT *FROM teacher ORDER BY age DESC;
id name age sex
1239 hello 26 1
1234 wsy 25 1
…
1235 wsy 20 0
8、Limit:查詢限制數(shù)量,offset查詢結(jié)果中的偏移量
sqlite> SELECT *FROM teacher LIMIT 2 OFFSET 2;
id name age sex
1235 wsy 20 0
1236 wsy 25 1
六、連表查詢
連表查詢最重要的是兩個之間有鏈接條件,所以設(shè)計表的時候需要考慮到表之間的關(guān)聯(lián)。
廢話不多說,通過例子說明,這里創(chuàng)建了一張任務(wù)表(task),和文件表(file),一個任務(wù)會有一個或多個附件:
任務(wù)表(task):
文件表(file):
任務(wù)表的創(chuàng)建,及添加數(shù)據(jù):
sqlite> CREATE TABLE IF NOT EXISTS task(taskId varchar(30) NOT NULL, name TEXT NOT NULL, content TEXT, PRIMARY KEY(taskId));
sqlite> INSERT INTO task VALUES(1234, 'work', 'work together');
sqlite> INSERT INTO task VALUES(1235, 'write document', 'Please write document’);
sqlite> INSERT INTO task VALUES(1236, 'play', 'Please play');
taskId name content
1234 work work together
1235 write document Please write document
1236 play Please play
文件表的創(chuàng)建,及添加數(shù)據(jù):
sqlite> CREATE TABLE IF NOT EXISTS file(fileId varchar(30) NOT NULL, name TEXT NOT NULL, taskId varchar(30) NOT NULL, PRIMARY KEY(fileId, taskId));
sqlite> INSERT INTO file VALUES('f1234', 'ppt', 1234);
sqlite> INSERT INTO file VALUES('f1235', 'word', 1234);
sqlite> INSERT INTO file VALUES('f1236', 'pdf', 1235);
sqlite> INSERT INTO file VALUES('f1237', 'image', 1235);
sqlite> INSERT INTO file VALUES('f1238', 'text', 1235);
fileId name taskId
f1234 ppt 1234
f1235 word 1234
f1236 pdf 1235
f1237 image 1235
f1238 text 1235
以上是所有的準備工作,下表開始使用連表查詢:
-
內(nèi)鏈接:
WHERE 攜帶的條件查詢相當于內(nèi)鏈接,當然你可以使用(INNER JOIN ON)只查詢滿足條件的數(shù)據(jù),例如:只有task.taskId=file.taskId才算合法數(shù)據(jù)
sqlite> SELECT task.taskId, task.name, file.fileId, file.name, file.taskId FROM task, file WHERE task.taskId=file.taskId;
taskId name fileId name taskId
1234 work f1234 ppt 1234
1234 work f1235 word 1234
1235 write docu f1236 pdf 1235
1235 write docu f1237 image 1235
1235 write docu f1238 text 1235
Run Time: real 0.000 user 0.000195 sys 0.000075
-
外鏈接:
會找到所有與左表對應(yīng)的數(shù)據(jù),如果沒有將為空,例如:task=1236沒有file,但結(jié)果也返回了task=1236的數(shù)據(jù)
task表作為左表:
sqlite> SELECT task.taskId, task.name, file.fileId, file.name, file.taskId FROM task LEFT JOIN file ON task.taskId=file.taskId;
taskId name fileId name taskId
1235 write document f1236 pdf 1235
1235 write document f1237 image 1235
1235 write document f1238 text 1235
1234 work f1234 ppt 1234
1234 work f1235 word 1234
1236 paly
task作為右表:
sqlite> SELECT task.taskId, task.name, file.fileId, file.name, file.taskId FROM file LEFT JOIN task ON task.taskId=file.taskId;
taskId name fileId name taskId
1234 work f1234 ppt 1234
1234 work f1235 word 1234
1235 write docu f1236 pdf 1235
1235 write docu f1237 image 1235
1235 write docu f1238 text 1235
-
復(fù)合查詢:
UNION:查詢A和B中,非重復(fù)的值,比如A(1,2),B(1,3)->(1,2,3)
UNION ALL:比如A(1,2),B(1,3)->(1,2,1,3)
sqlite> SELECT taskId FROM file UNION SELECT taskId FROM task;
INTERSECT:交集,A(1,2),B(1,3)->(1)
sqlite> SELECT taskId FROM file INTERSECT SELECT taskId FROM task;
EXCEPT:差集,A(1,2),B(1)->(2)
sqlite> SELECT taskId FROM task EXCEPT SELECT taskId FROM file;
-
子查詢:
SELECT語句中又嵌套了SELECT語句
sqlite> SELECT *FROM task WHERE taskId IN(SELECT DISTINCT taskId FROM file);
taskId
1234
1235
查詢?nèi)蝿?wù)中附件的個數(shù):
SELECT *, (SELECT COUNT(fileId) FROM file WHERE task.taskId=taskId) AS file_count FROM task;
taskId name content file_count
1235 write document Please write document today 3
1234 work work together 2
1236 play Please play 0
七.數(shù)據(jù)更新
如果對插入數(shù)據(jù)庫中的數(shù)據(jù)更新,執(zhí)行update操作。
格式:
UPDATE table SET update_list WHERE predicate;
以teacher表為例:
更新id=1234的年齡為28,sex=0
sqlite> UPDATE teacher SET age=28, sex=0 WHERE id=1234;
主鍵不能更新
sqlite> UPDATE teacher SET name=haha WHERE id=1234;
sqlite> UPDATE teacher SET name='haha', id=1240 WHERE sex=0;
sqlite> UPDATE teacher SET id='haha' WHERE sex=0;
Error: UNIQUE constraint failed: teacher.id, teacher.name
八、數(shù)據(jù)刪除:
刪除數(shù)據(jù)中的數(shù)據(jù)
例如:刪除id=1234的數(shù)據(jù)
sqlite> DELETE FROM teacher WHERE id=1234;
九、修改表:
格式:
ALTER TABLE table_name {RENAME TO name | ADD COLUMN column_name 約束}
為teacher表添加一列address,默認值為空字符串
sqlite> ALTER TABLE teacher ADD COLUMN address TEXT DEFAULT ‘';
修改teacher表為teacher2
sqlite> ALTER TABLE teacher RENAME TO teacher2;
注意表的主鍵是不能修改的;
十、創(chuàng)建索引:
索引是一種用來在某種條件下加速查詢的結(jié)構(gòu)。但是創(chuàng)建索引后,數(shù)據(jù)表的大小會增大,而且可能會降低insert、update的操作速度,因為修改表的同時,數(shù)據(jù)庫也必須修改對應(yīng)的索引。所有創(chuàng)建索引的時候,要選擇執(zhí)行查詢比較頻繁的字段。
格式:
CREATE INDEX [UNIQUE] index_name ON table_name (columns)
index_name:索引的名字
table_name:表名字
columns:索引的列名,列之間用逗號隔開
[UNIQUE]:表示創(chuàng)建的是唯一索引,它是可選的
例如給teacher表創(chuàng)建一個索引:
sqlite> CREATE INDEX teacher_id ON teacher(id);
刪除索引:
sqlite> DROP INDEX index_name;
十一、創(chuàng)建視圖:
視圖也叫虛擬表,是從基本表中動態(tài)產(chǎn)生的數(shù)據(jù)。
在連表查詢中的內(nèi)連接,使用:
sqlite> SELECT task.taskId, task.name, file.fileId, file.name, file.taskId FROM task, file WHERE task.taskId=file.taskId;
來查詢數(shù)據(jù),但是如果有很多這樣的情況,你會感到很厭煩,那么創(chuàng)建視圖是一個很好的選擇:
sqlite> CREATE VIEW task_file AS SELECT task.taskId, task.name, file.fileId, file.name, file.taskId FROM task, file WHERE task.taskId=file.taskId;
這樣你可以直接在視圖中查找:
sqlite> SELECT *FROM task_file;
taskId name fileId name:1 taskId:1
1234 work f1234 ppt 1234
1234 work f1235 word 1234
1235 write docu f1236 pdf 1235
1235 write docu f1237 image 1235
1235 write docu f1238 text 1235
Run Time: real 0.000 user 0.000202 sys 0.000075
十二、事務(wù):
事務(wù)定義了一組SQL命令的邊界,這組命令或者作為一個整體被全部執(zhí)行,或者都不執(zhí)行。比如銀行轉(zhuǎn)賬,A想B轉(zhuǎn)賬500,A賬戶減少500,B賬號多500,如果在轉(zhuǎn)賬的過程中電力中斷或者其他意外情況發(fā)生,那么必須中斷此次操作。
一個事務(wù)的例子:
開始執(zhí)行一個事務(wù):
sqlite> begin;
刪除表teacher2中所有數(shù)據(jù):
sqlite> delete from teacher2;
查詢teacher2表中數(shù)據(jù),無數(shù)據(jù)
sqlite> select *from teacher2;
回滾,這里也可以是commint,提交后將執(zhí)行刪除操作
sqlite> rollback;
查詢teacher2表中數(shù)據(jù),結(jié)果如下:
sqlite> select *from teacher2;
id name age sex
1235 wsy 20 0
1236 wsy 25 1
1238 good 25 1
1238 hello 25 1
1239 hello 26 1
十三、數(shù)據(jù)完整性
數(shù)據(jù)完整性用于定義和保護表內(nèi)部或表之間的數(shù)據(jù)關(guān)系,主要有以下四種完整性:
1.域完整性
控制字段內(nèi)的值,也就是字段值遵從賦予的規(guī)定,比如添加約束
默認值:
CREATE TABLE student(id TEXT, name TEXT DEFAULT ‘UNKNOWN’);
另外默認值可以是:
date not null default current_date // 2015-12-22
time not null default current_time // 00:59:05
timestamp not null default current_timestamp // 2015-12-22 01:00:16
2.實體完整性
數(shù)據(jù)庫中表的行必須在某種方式上是唯一的,這就是主鍵的功能。實體完整性基本保持表中的數(shù)據(jù)是可尋址的,如果找不到數(shù)據(jù),那還有什么意義?
唯一性約束:(UNIQUE)
要求一個或一組字段的所有值均不相同,如果插入重復(fù)的值,數(shù)據(jù)庫將引發(fā)一個非法約束的錯誤。CREATE TABLE student(id TEXT, name TEXT, age INT, UNIQUE(id, name));主鍵約束:
當你定義一個表的時候,總會指定一個主鍵,不管你有沒有指定,都會有一個rowid來充當主鍵。你可以使用SQL語句找到它:SELECT rowid FROM student;NOT NULL約束:
插入或更新數(shù)據(jù)時不能為NULLCHECK約束:
允許定義表達式來驗證要插入或者更新的字段值是否滿足表達式,如果不滿足講不能插入。
3.用戶自定義完整性
十四、一些技巧:
執(zhí)行語句的時候添加:explain query plan,可以查詢計劃
sqlite_master表是系統(tǒng)表,它包含所有表,視圖,索引和觸發(fā)器的信息
sqlite> select *from sqlite_master;表的信息
sqlite> pragma table_info(teacher2);索引的信息:
sqlite> pragma index_info(taskId_index);如果一列數(shù)據(jù)的數(shù)據(jù)類型不一樣,排序?qū)凑找韵路绞脚判颍?br> NULL,INTEGER, REAL, TEXT, BLOB
十五、寫在最后
由于項目對數(shù)據(jù)庫采取了加密,每次出現(xiàn)bug的時候總想到數(shù)據(jù)庫中找一下數(shù)據(jù)是否異常,可使用sqlite工具的時候必須下載包,然后找到數(shù)據(jù)庫,這時打開數(shù)據(jù)庫,發(fā)現(xiàn)數(shù)據(jù)庫是加密的,即使輸入正確的密碼也不能查看數(shù)據(jù)庫中的數(shù)據(jù),每次感覺很頭疼。最后實在沒辦法,自己寫了一個查看數(shù)據(jù)庫的小工具(
PMFMDB-iOS ),寫的很粗糙,不過一直使用,感覺還行。
===== 我是有底線的 ======
喜歡我的文章,歡迎關(guān)注我的新浪微博 Lefe_x,我會不定期的分享一些開發(fā)技巧