IOS - 關于移動端SQLite,你想知道的都有
一、SQLite簡介
SQLite,是一款輕型的數據庫,是遵守 ACID 的關系型數據庫管理系統,它包含在一個相對小的C庫中。它是D.RichardHipp建立的公有領域項目。它的設計目標是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它占用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統,同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源的世界著名數據庫管理系統來講,它的處理速度比他們都快。
二、SQLite優勢
- 1、占用資源低
- 2、速度快
- 3、與其他數據庫相比,更適配移動平臺、嵌入式平臺
三、SQLite支持的存儲類型有:
1、INTEGER - 整形
2、blob - 二進制
3、real - 浮點型
4、text - 字符串
5、NULL - 空
注意: 在SQLite中大小寫不區分,也就是AA = aA = Aa = aa
四、SQLite學習之DDL
DDL(Data Definition Language):數據定義語言,用來創建數據庫中的各種對象-----表、視圖、
索引、同義詞、聚簇等
- 創建表
CREATE TABLE 表名 (字段名 字段類型,字段名1 字段類型1,...);
- 刪除表
DROP TABLE 表名;
DDL - 創建表:
<br />
CREATE TABLE T_Person(id INTEGER, name TEXT,age INTEGER);
在這里我們通常有兩種書寫格式,假設語句不是很長的情況下,
可以寫成一行,但是如果語句過長就不利于閱讀,所以有了下面的格式:
CREATE TABLE T_Person
(
id INTEGER,
name TEXT,
age INTEGER
);</code></pre>
通過上述代碼我們就可以創建一個表了,但是如果在執行一次上面的語句, 就會發現報錯了,
錯誤:文件已存在 Error : table T_Person already exists
所以我們創建的時候需要判斷表是不是存在
于是有了下面的創建語句:
CREATE TABLE IF NOT EXISTS T_Person
(
id INTEGER,
name TEXT,
age INTEGER
);
其中
IF NOT EXISTS : 如果不存在
上面創建的語句翻譯就是:
創建一個表,如果不存在的話就創建
DDL - 刪除表:
DROP TABLE T_Person;
五、SQLite學習之DML
DML(Data Manipulation Language)數據庫操作語句:
關鍵字有insert,update,delete
分別對應:插入、更新、刪除
- 插入數據
INSERT INTO 表名(字段...) VALUES(值...);
- 更新數據
UPDATE 表名 SET 字段名=值,...;
- 刪除數據
DELETE FROM 表名;
DML - 插入數據:
INSERT INTO T_Person1 (name,age) VALUES('zs',20);
在現實生活中我們可能會遇到這樣一種情況:
在一個班里,有可能有兩個人的姓名完全一致,這個時候我們
就需要進行區分,就像每個人都有一個身份證號,且唯一</code></pre>

這個時候如何區分?
如果想保證數據唯一:
這個時候就需要主鍵: PRIMARY KEY ,所以我們要修改我們的創建表的語句
修飾主鍵的方法有兩種:
- 方法一:
CREATE TABLE T_Person
(
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
);
- 方法二:
CREATE TABLE IF NOT EXISTS T_Person1
(
id INTEGER,
name TEXT,
age INTEGER,
PRIMARY KEY (id)
);
這個時候我們再次執行插入語句
INSERT INTO
T_Person1 (id,name,age)
VALUES(1,'zs',20);
.
第一次:Affected rows : 1, Time: 0.00sec
第二次:Error : UNIQUE constraint failed: T_Person1.id
從上面的結果可以看出,id不能相同,那怎么樣才能保證ID不相同,
又不輸入id這個屬性呢?因為人輸入,可能會存在差錯,交給機器做最好。
于是我們要用到個新的關鍵字: AUTOINCREMENT 自增
所以我們還要在修改一次創建語句:
CREATE TABLE IF NOT EXISTS T_Person1
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
age INTEGER
);
現在我們就可以肆無忌憚的執行下面這條插入語句了
INSERT INTO
T_Person1 (name,age)
VALUES('zs',20);
下面是執行了5次的之后的表:

執行了5次之后
現在我們完全可以不用管理ID這個字段,并且現在每一條數據都是唯一的。
但是在某些情況下還是會有不完善的地方,比如下面這條插入語句:
INSERT INTO
T_Person1 (age)
VALUES(35);
然后我們來查看一下表:

插入了一條姓名為空、年齡是35的數據
這樣子看似乎沒有問題,但是結合實際情況來看,假設這是一個班級的數據,我不希望我的學生連名字都沒有,這個不像話。
然后沒錯,又要使用一個新的關鍵字: NOT NULL 不為空
然后再次更新表的創建語句:
CREATE TABLE T_Person1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
);
然后我們再次執行上面的語句
INSERT INTO
T_Person1 (age)
VALUES(35);
錯誤提示:Error : NOT NULL constraint failed: T_Person1.name
這個時候就會報錯:提示我們名字不能為空
于是我們要寫成:
INSERT INTO
T_Person1 (name,age)
VALUES('xiaoming',35);
提示:Affected rows : 1, Time: 0.00sec
再次查看表:

插入數據
然后我們在介紹一個屬性: DEFAULT 默認值
使用方法就是在字段名后面
age INTEGER DEFAULT 15
表示定義了一個age 字段 默認是15
這個時候我們的創建表語句如下:
CREATE TABLE T_Person1 (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER DEFAULT 15
);
然后我們插入數據:
INSERT INTO T_Person1 (name) VALUES('zs');
INSERT INTO T_Person1 (name,age) VALUES('ls',18);
INSERT INTO T_Person1 (name,age) VALUES('zs',25);
INSERT INTO T_Person1 (name) VALUES('zl');
表如下:

數據表圖
通過上面的了解我們就知道如何插入數據,并且設置字段了。
DML - 更新數據:
UPDATE T_Person1 SET name='qq';
執行這行語句后會發現所有的名字都變成了qq
更新多個字段
UPDATE T_Person1 set name='qq',age=20;
如圖:

更新數據之后
在上面的代碼中我們已經完成了對數據庫的更新,但是卻不是我們想要的結果,上面的是對整個數據庫都進行了更新,如果我們只想對某個數據更新改如何解決呢?后面會講到
DML-刪除:
DELETE FROM T_Person1;
執行完上面語句之后查看打印:
Affected rows : 4, Time: 0.00sec 影響了四行數據
然后我們再來看表

空空如也
這個時候我們就已經完成了對DML的學習,但是這些還不夠,比如我們更新數據的時候是對整個表進行更新,
刪除也是把整個表進行刪除,如果我們想對指定的數據進行操作,我們需要學習一個新的關鍵字:
WHERE 條件
WHERE
SQLite的 WHERE 子句用于指定從一個表或多個表中獲取數據的條件。
如果滿足給定的條件,即為真(true)時,則從表中返回特定的值。您可以使用 WHERE 子句來過濾記錄,只獲取需要的記錄。
SQLite的運算符有四種:算數、比較、邏輯以及位運算符
算數運算符:
+ 加法 - 把運算符兩邊的值相加 a + b 將得到 30
- 減法 - 左操作數減去右操作數 a - b 將得到 -10
- 乘法 - 把運算符兩邊的值相乘 a * b 將得到 200
/ 除法 - 左操作數除以右操作數 b / a 將得到 2
% 取模 - 左操作數除以右操作數后得到的余數 b % a will give 0</code></pre>
比較運算符
== 檢查兩個操作數的值是否相等,如果相等則條件為真。 (a == b) 不為真。
= 檢查兩個操作數的值是否相等,如果相等則條件為真。 (a = b) 不為真。
!= 檢查兩個操作數的值是否相等,如果不相等則條件為真。 (a != b) 為真。
<> 檢查兩個操作數的值是否相等,如果不相等則條件為真。 (a <> b) 為真。
> 檢查左操作數的值是否大于右操作數的值,如果是則條件為真。 (a > b) 不為真。
< 檢查左操作數的值是否小于右操作數的值,如果是則條件為真。 (a < b) 為真。
= 檢查左操作數的值是否大于等于右操作數的值,如果是則條件為真。 (a >= b) 不為真。
<= 檢查左操作數的值是否小于等于右操作數的值,如果是則條件為真。 (a <= b) 為真。
!< 檢查左操作數的值是否不小于右操作數的值,如果是則條件為真。 (a !< b) 為假。
!> 檢查左操作數的值是否不大于右操作數的值,如果是則條件為真。 (a !> b) 為真。
邏輯運算符:
AND AND 運算符允許在一個 SQL 語句的 WHERE 子句中的多個條件的存在。
BETWEEN BETWEEN 運算符用于在給定最小值和最大值范圍內的一系列值中搜索值。
EXISTS EXISTS 運算符用于在滿足一定條件的指定表中搜索行的存在。
IN IN 運算符用于把某個值與一系列指定列表的值進行比較。
NOT IN IN 運算符的對立面,用于把某個值與不在一系列指定列表的值進行比較。
LIKE LIKE 運算符用于把某個值與使用通配符運算符的相似值進行比較。
GLOB GLOB 運算符用于把某個值與使用通配符運算符的相似值進行比較。GLOB 與 LIKE 不同之處在于,它是大小寫敏感的。
NOT NOT 運算符是所用的邏輯運算符的對立面。比如 NOT EXISTS、NOT BETWEEN、NOT IN,等等。**它是否定運算符。**
OR OR 運算符用于結合一個 SQL 語句的 WHERE 子句中的多個條件。
IS NULL NULL 運算符用于把某個值與 NULL 值進行比較。
IS IS 運算符與 = 相似。
IS NOT IS NOT 運算符與 != 相似。
|| 連接兩個不同的字符串,得到一個新的字符串。
UNIQUE UNIQUE 運算符搜索指定表中的每一行,確保唯一性(無重復)。
位運算符:
& 與
| 或
p q p & q p | q
0 0 0 0
0 1 0 1
1 1 1 1
1 0 0 1
在了解了WHERE之后呢我們就可以對數據庫進行指定某條刪除、更新等操作了
先向數據庫中 插入一些數據
INSERT INTO T_Person1 (name,age) VALUES('aa',20);
INSERT INTO T_Person1 (name,age) VALUES('bb',18);
INSERT INTO T_Person1 (name,age) VALUES('cc',24);
INSERT INTO T_Person1 (name,age) VALUES('dd',22);
INSERT INTO T_Person1 (name,age) VALUES('ee',19);
INSERT INTO T_Person1 (name,age) VALUES('ff',22);
INSERT INTO T_Person1 (name,age) VALUES('gg',19);
INSERT INTO T_Person1 (name,age) VALUES('hh',18);
然后數據表中數據如下:

數據圖
DML-更新/刪除指定數據
UPDATE
T_Person1
set
name='ff',age=20
WHERE
name='bb';
表示我要更新一個姓名叫做bb的人數據,并且把他的名字設置為qq、年齡設置為20歲
Affected rows : 1, Time: 0.00sec 提示已經影響了一條數據</code></pre>
此時查看表如下:

更新了之后
如果你足夠細心,你就發現了現在有兩個人名字都叫ff了,如果我現在只想對第一個姓名叫ff的人更新數據
我們可以這樣子寫:
UPDATE
T_Person1
set
name='ee',age=19
WHERE
name='ff' AND age=20;
然后表現在的數據如下:

更新數據之后
OK,通過上面的語句我們完成了只對第一個名字叫ff的人更新數據,但是現在我想對
第二個姓名為ee進行更新,就很尷尬了,數據庫中有兩個姓名都叫ee的并且年齡都是19歲,
到了這里我們定義id為唯一的作用就發揮出來了,此時我們只需要更新
指定id即可
UPDATE
T_Person1
set
name='bb',age=28
WHERE
id=9;
更新之后如圖:

更新之后
OK,通過上面的代碼我們就可以知道如何對指定的數據進行更新了,下面我們簡單的說下刪除指定數據.
DELETE FROM
T_Person1
WHERE
name='gg';
如圖:

刪除之后
如果我想刪除多條數據呢?
比如刪除20歲以上的
DELETE FROM
T_Person1
WHERE
age>20;
Affected rows : 4, Time: 0.00sec 影響了四行,應該是刪除了四行,
我們查看更新之后的表</code></pre>
表:

刪除之后
七、SQLite學習之DQL:
DQL(Data Query Language)數據查詢語言
關鍵字:Select,同時也是使用頻率最高的
查詢數據
SELECT 字段名,... FROM 表名;
先插入一下數據進去
INSERT INTO T_Person1 (name,age) VALUES('ab',28);
INSERT INTO T_Person1 (name,age) VALUES('hg',25);
INSERT INTO T_Person1 (name,age) VALUES('ab',24);
INSERT INTO T_Person1 (name,age) VALUES('df',22);
INSERT INTO T_Person1 (name,age) VALUES('fd',23);
INSERT INTO T_Person1 (name,age) VALUES('yt',28);
INSERT INTO T_Person1 (name,age) VALUES('oi',21);
INSERT INTO T_Person1 (name,age) VALUES('qw',33);
INSERT INTO T_Person1 (name,age) VALUES('gf',19);
INSERT INTO T_Person1 (name,age) VALUES('kl',18);
INSERT INTO T_Person1 (name,age) VALUES('lj',23);
INSERT INTO T_Person1 (name,age) VALUES('rt',25);
INSERT INTO T_Person1 (name,age) VALUES('tr',28);
INSERT INTO T_Person1 (name,age) VALUES('qw',26);
INSERT INTO T_Person1 (name,age) VALUES('xx',24);
INSERT INTO T_Person1 (name,age) VALUES('zx',25);
INSERT INTO T_Person1 (name,age) VALUES('mn',24);
INSERT INTO T_Person1 (name,age) VALUES('vb',25);
然后可以看到表數據如下:

數據表如圖
OK,在填充了數據之后,我們開始查找
SELECT * FROM T_Person1;
在這里*代表通配符,所有的字段
如圖:

查找之后
現在我們不想看到那么多數據,假設我們只顯示age
SELECT age FROM T_Person1;
如圖所示

單個字段
查詢多個字段: 這里字段的輸入順序就和顯示的列名數據一致
SELECT age,name FROM T_Person1;
如圖:

多個字段
OK,需求總是要變來變去的,這個時候我們想查詢年齡大于22歲的數據,并且顯示所有的信息
SELECT * FROM T_Person1 WHERE age>22;
如圖:

條件查詢
然后我們想找名字為ab的人,不要顯示id
SELECT name,age FROM T_Person1 WHERE name='ab';
如圖:

條件查詢二
如果你看到了這里,那么恭喜你,你已經知道了如何創建/刪除表,以及對表的增刪改查,同時還了解了WHERE條件語句,到這里基本上你已經可以自己管理數據庫了。
擴展知識 - 動態添加字段
繼續上面的表,這個時候老師分配任務啦,給每個人100塊的啟動資金,然后一個月后來查看他們是讓100塊變成了0塊還是變成了更多,這個時候上面就來話了,你給我添加一個字段進去,保存他們的金錢額度。
但是這個需求在項目開始之初是沒有考慮到的,這就比較坑爹了,原來的數據庫文件的內容不能刪除,又要新增一個字段……愁死我了。
方法有很多種,這里不作介紹了
只是來介紹一下動態添加字段這個方法
ALTER TABLE 表名 ADD 字段名 字段類型;
未插入字段之前的表:

未插入之前
插入一個字段:money
ALTER TABLE
T_Person1
ADD
money real DEFAULT 100.0;

插入之后
OK,到這里完美解決了之前的問題
注意:再插入一個字段之前,講道理我們是要看下里面有沒有這個字段的
比如你正在上廁所,突然有個人就進來把你趕出去了,占了你的坑,此時的你肯定是在暴怒狀態,正常的應該是:先看下里面有沒有人,有人了就換一個,沒人然后在進去占一個坑……
所以我們需要判斷一下是不是可以插入這個字段
SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
通過上面的方法會返回給我們一個C字符串數組判斷這個數組是不是有值,如果有了就不能插入了
為此我特地的又運行了一次
Error : duplicate column name: money
提示說有兩個都叫money的列了
擴展知識 - AS(起別名)
可以暫時把表或列重命名為另一個名字,這被稱為 別名 。使用表別名是指在一個特定的 SQLite 語句中重命名表。重命名是臨時的改變,在數據庫中實際的表的名稱不會改變。
列別名用來為某個特定的 SQLite 語句重命名表中的列。
比如:給字段起別名
SELECT
name as xingming,
age as nianling
FROM
T_Person1
WHERE
age>25;
如圖:

字段別名
給表起別名:
SELECT
one.name as one_name,
one.age as one_age
FROM
T_Person1 as one
WHERE age>25;
如圖:

表別名
多表查詢:
先創建一個T_Person2表,然后插入一下數據
CREATE TABLE IF NOT EXISTS
T_Person2(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER DEFAULT 20,
money REAL DEFAULT 100.0
);
INSERT INTO T_Person2 (name,age) VALUES('asdf',28);
INSERT INTO T_Person2 (name,age) VALUES('hsdfg',25);
INSERT INTO T_Person2 (name,age) VALUES('afdfb',24);
INSERT INTO T_Person2 (name,age) VALUES('dfasdf',22);
INSERT INTO T_Person2 (name,age) VALUES('ffdfd',23);
INSERT INTO T_Person2 (name,age) VALUES('yfdft',28);
INSERT INTO T_Person2 (name,age) VALUES('ocvi',21);
INSERT INTO T_Person2 (name,age) VALUES('qwvc',33);
INSERT INTO T_Person2 (name,age) VALUES('gvcvf',19);
INSERT INTO T_Person2 (name,age) VALUES('kcvcl',18);
INSERT INTO T_Person2 (name,age) VALUES('lvj',23);
INSERT INTO T_Person2 (name,age) VALUES('rvcdst',25);
INSERT INTO T_Person2 (name,age) VALUES('tr43',28);
INSERT INTO T_Person2 (name,age) VALUES('qwgh',26);
INSERT INTO T_Person2 (name,age) VALUES('xgfdx',24);
INSERT INTO T_Person2 (name,age) VALUES('hfgzx',25);
INSERT INTO T_Person2 (name,age) VALUES('mgfhn',24);
INSERT INTO T_Person2 (name,age) VALUES('vhgb',25);</code></pre>
這個時候,T_Person1里面有的字段T_Person2里面也有,就想兩個班級里面的字段
都有姓名,年齡等數據。
別名這個時候就可以很方便的區分
SELECT
one.name as one_name,
one.age as one_age,
two.name as two_name,
two.age as two_age
FROM
T_Person1 as one,
T_Person2 as two
WHERE
one.age>30 AND two.age>30;
如圖:

如圖
寫別名的方式還有一種,但是不推薦,直接加個空格
SELECT name xingming,age nianling
FROM T_Person2;
如圖:

別名
擴展知識 - 排序
ORDER BY ,用于對數據進行排序
考慮這么一種情況,當你把數據信息輸入進去,而數據本身是雜亂無章的,這個時候你需要排序,比如:name、age字段來排序。
DESC : 降序
ASC:升序
單個字段排序
SELECT
*
FROM
T_Person2
ORDER BY
age;</code></pre>
如圖:根據age升序

單個字段排序
多個字段排序
SELECT
*
FROM
T_Person2
ORDER BY
name,age;</code></pre>
如圖:根據name升序,在根據age升序

多個字段排序
通過上面的語句我們發現在不寫明是什么排序的情況下默認是升序,也就是 ASC
通過寫上ASC來證明:
SELECT
*
FROM
T_Person2
ORDER BY
name ASC,age ASC;</code></pre>
如圖:

表
下面根據age字段進行降序
SELECT
*
FROM
T_Person2
ORDER BY
age DESC;
如圖:

age降序
最后我們在實現一個根據name升序,age降序的
先別著急,因為我們數據庫中沒有相同姓名的,所以我們先插入兩條數據
插入數據
INSERT INTO T_Person1(name,age) VALUES('aa',18);
INSERT INTO T_Person1(name,age) VALUES('aa',19);
檢索
SELECT
*
FROM
T_Person1
ORDER BY
name ASC,age DESC;
如圖:

檢索如圖
擴展知識 - 數量
快速查詢有多少條數據或者查詢某個字段有多少條數據
SELECT COUNT(字段) FROM 表名;
查詢有多條數據:
SELECT COUNT(*) FROM T_Person1;
如圖

檢索
檢索 age 字段條數:
SELECT COUNT(age) FROM T_Person1;

age
擴展知識 - 分頁取數據
Limit 常用來對數據進行分頁,比如每頁固定顯示 n 條數據
SELECT 字段... FORM 表名 LIMIT a,b;
a:表示跳過多少條數據
b:從a之后開始取多少條數據
在網絡請求的時候我們經常可以向服務器說明,從哪一頁開始,取多少條,類似這樣子的操作很頻繁。
舉例:每頁取10條數據
- 第1頁:... LIMIT 0,10;
- 第2頁:... LIMIT 10,10;
- 第3頁:... LIMIT 20,10;
- ...
- 第n頁:... LIMIT 10*(n-1),10;
于是我們可以得出一個公式:
m:每次取多少
n:頁
m*(n-1),m
注意:LIMIT 10 = LIMIT 0,10,兩個語句相等
代碼:取10條數據,從0開始
SELECT * FROM T_Person1 LIMIT 10;
如圖:

limit
如果我們數據庫中沒有那么多的情況下,就會把剩下的全部都取出來
比如: T_Person1 中我們只有 23 條數據,在上面檢索出來過
執行:
SELECT * FROM T_Person1 LIMIT 20,10;
如圖:

limit 20,10
OK,進一步增加難度,我要取得age>20的前面10條數據
SELECT *
FROM T_Person1
WHERE age>20
LIMIT 10;

檢索age大于20的數據,取十條

表
然后我們在聯合排序提取數據:
SELECT *
FROM T_Person1
ORDER BY age DESC
LIMIT 10;
如圖

根據age進行排序(降序),取前面十條
對比查看數據是不是正確

對比
通過兩個圖比較,發現取出來的數據確實是正確的。
文中一些比較簡短的語句其實沒比較分行分的那么清楚,只是筆者為了能讓人閱讀起來更加方便,有寫筆者也沒有進行分行,不過閱讀起來應該還是比較簡單的。
OK,如果你堅持看完了,希望或多或少能給你帶來一些小小的幫助。
筆者寫這個也花了一點時間,如果能讓您復習或者有幸讓你更了解SQLite的話,就不枉費這些時間了。
最后厚著臉皮求個喜歡,那是我最大的動力。后面會更新如何在Swift3.0的中使用。
來自:http://www.jianshu.com/p/4bc34f982fee