說明
本文是作者Lefe所創(chuàng)狰住,轉(zhuǎn)載請注明出處景鼠,如果你在閱讀的時候發(fā)現(xiàn)問題歡迎一起討論葛菇。本文會不斷更新从媚。
正文
對于iOS應用逞泄,我相信有很多人還選擇使用sqlite作為數(shù)據(jù)的持久化操作,但是對于一個還沒有接觸過sqlite的同學難免會有點不知所措,我記得我曾經(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
二毁腿、終端使用技巧:
當你學習使用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),復合主鍵稽煤,創(chuàng)建表的時候可以使用復合主鍵核芽,保證復合主鍵中的一列唯一即可,比如(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察藐,由于復合主鍵的原因皮璧,(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中的一一對應。
向teacher表中插入一條記錄:
INSERT INTO teacher(id, name, age, sex) VALUES (1234, 'wangsuyan', 25, 1);
插入數(shù)據(jù)的時候也可以省略字段名稱(列名),字段名稱必須和值一一對應
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闸准、去重益愈,去掉重復的字段,注意以下語句的不同
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
六阳啥、連表查詢
連表查詢最重要的是兩個之間有鏈接條件添谊,所以設計表的時候需要考慮到表之間的關(guān)聯(lián)。
廢話不多說察迟,通過例子說明,這里創(chuàng)建了一張任務表(task)耳高,和文件表(file),一個任務會有一個或多個附件:
任務表(task):
文件表(file):
任務表的創(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
-
外鏈接:
會找到所有與左表對應的數(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
-
復合查詢:
UNION:查詢A和B中修壕,非重復的值愈捅,比如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)蝿罩懈郊膫€數(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ù)庫也必須修改對應的索引。所有創(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
十二寡润、事務:
事務定義了一組SQL命令的邊界,這組命令或者作為一個整體被全部執(zhí)行舅柜,或者都不執(zhí)行梭纹。比如銀行轉(zhuǎn)賬,A想B轉(zhuǎn)賬500致份,A賬戶減少500变抽,B賬號多500,如果在轉(zhuǎn)賬的過程中電力中斷或者其他意外情況發(fā)生氮块,那么必須中斷此次操作绍载。
一個事務的例子:
開始執(zhí)行一個事務:
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)
要求一個或一組字段的所有值均不相同肮韧,如果插入重復的值,數(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ā)技巧