相信看了我博客的上篇的博友或路過者,都會覺得,sqlite小巧,易學,簡單。下面是我再把我的筆記上傳博客中,以幫助一些人和我自己,今后翻閱方便。因為我知道有這回事。
前幾天看到有人回復帖子問了sqlite數據庫用在哪些方面,其實這樣的問題,都可以維基或是百度下的,什么都會出來,不過sqlite是小型的數據庫,主要用在嵌入式設備中如手機等。下面是對這sqlite3的一些注意和高級部分的筆記:
1、類型自動分類:具體的值比如sql語句部分的帶雙引號或單引號的文字被定為Text;如果文字沒帶引號和小數點或指數則被定義為INTEGER;如果文字沒帶引號但有小數點或指數則被定義為REAL;如果值是空則被定義為空值;BLOB數據使用符號X'ABCD'標識。
2、sqlite3.0中,值被定義為什么類型只和值自身有關,和列、變量都沒關系,我們稱其其為“弱類型”。所有其他的數據庫引擎都收靜態類型系統的限制,其中的所有值的類型是由其所屬列的屬性決定的,而和值無關。不過為了最大限度的增加sqlite和其他數據庫的兼容性,sqlite提出了一個“類型親和性”,意思就是說它支持列的“類型親和性”。列的“類型親和性”是為該列所存儲的數據建議一個類型。我們還要注意是建議不是強迫。在理論上講,任何列上可以存儲任何類型的數據。只是針對某些列,如果給建議類型的話,數據庫將按所建議的類型存儲,而這個被優先使用的數數據類型則被稱為“親和類型”。
(1)、sqlite3.0中,數據庫的每一列都被定義為以下親和類型的一種:文本、數字(實數)、整數、無。(這點的理解是這樣的,就是說我給一個整數類型的值填充到文本字段上,此時整數類型的數據被當作文本存儲。)
規則:
(1)、 如果數據類型包括字符串"INT"那么它被定義成具有整數親和性.
(2)、 如果列中的數據類型包括以下任何的字符串 "CHAR", "CLOB", or "TEXT" 那么這個列則具有文本親和性.要注意VARCHAR 類型包括字符串"CHAR"因此也具有文本類型親和性.
(3)、如果一個列的數據類型包括字符串"BLOB"或者如果數據類型被具體化了,那么這個列具有無類型親和性.
(4)、否則就具有數字(實數)類型親和性.
3、 運算符
所有的數學運算符(所有的運算符而不是連鎖作用標記符"||")運算對象首先具有數字親和性, 如果一個或是兩個都不能被轉換為數字那么操作的結果將是空值。 對於連接作用操作符,所有操作符將首先具有文本親和性。如果其中任何一個操作符不能被轉換為文本(因為它是空值或是 BLOB)連接作用操作符將是空值。
4、 分類,排序,混合挑選
當用子句 ORDER挑選值時,空值首先被挑選出來, 然后是整數和實數按順序被挑選出來, 然后是文本值按 memcmp()順序被挑選出來, 最后是BLOB值按memcmp()順序被挑選出來.在挑選之前, 沒有存儲類型的值都被轉換了。
5、用戶定義的校對順序
BINARY -使用memcmp()比較字符串數據, 不考慮文本編碼。(默認比較順序)
REVERSE -用倒序比較二進制文本。
NOCASE - 和二進制一樣,但在比較之前,26 位的大寫字母要被轉換成小寫字母。【這個改變可以通過編寫sqlite的自定義函數自己實現一些數據庫函數就可以,而且這些自定義函數,在sqlite api中都有。寫好了后,進行編譯,生成.exe文件就可以。】
對於二進制比較符(=, <, >, <= and >=),如果操作數是一列的話,那么該列的默認比較類型決定於所使用的比較順序. 如果兩個操作數都是列的話,那么左邊的操作數的默認比較類型決定了所要使用的比較順序.如果兩個操作數都不是一列,將使用二進制來比較。
6、SQLite 不支持的 SQL92 特性
這個列表的順序關系到何時一個特性可能被加入到 SQLite。接近列表頂部的特性更可能在不遠的將來加入。接近列表底部的特性尚且沒有直接的計划。
7、sqlite不支持成群的索引(簡單來說,就是索引使數據庫中的數據存入時索引的順序是什么樣,數據怎樣放置),這意味着,如果你的索引的是整數順序,記錄就會把數據庫中的數據按整數順序安排,先1后2后3。(設置sqlite頁面緩存: pragma page_size=大小;)
看個例子:create table wibble2 as select * from wibble;
Delete from wibble;
Insert into wibble select * from wibble2 order by key;(這行的寫法,在其他數據庫試過,可行(Oracle/SQLServer2012),sqlite3中也支持)
Drop table wibble2;
8、sqlite中如何使用觸發器執行取消和重做邏輯:思路是創建一個特殊表格, 保存數據庫撤銷和重做變化所需的信息。因為數據庫中的每個表格都需要參與撤銷和重做,每個delete、insert、update都生成了觸發器,而且它們可以在撤銷日記表格中生成登記項,這個登記項將撤銷操作。撤銷表格中的登記項由一般的sql語句組成,為了完成撤銷,sql語句可以重新運行。
CREATE TRIGGER 觸發器名稱 [BEFORE|AFTER] 數據庫事件 ON [數據庫名稱].表名 [FOR EACH ROW][ WHEN expression] BEGIN 觸發器執行動作 END |
數據庫事件: DELETE INSERT UPDATE UPDATE OF 字段列表 |
下面寫個腳本:
Create table ex1(a INTEGER, b TEXT, c REAL);
Create trigger trigger_ex1_it
after insert on ex1
Begin
Insert into undolog values(NULL, 'delete from ex1 where rowid='||new.rowid);
End;
Create trigger trigger_ex1_ut
after update on ex1
Begin
Insert into undolog values(NULL,'update ex1 set a='||quote(old.a)||',b='||quote(old.b)||', c='||quote(old.c)||' where rowid='||old.rowid);
End;
Create trigger trigger_ex1_dt
Before delete on ex1
Begin
Insert into undolog values(NULL, 'insert into ex1(rowid, a, b, c) values('||old.rowid||', '||quote(old.a)||', '||quote(old.b)||','||quote(old.c) ||')');
End;
在ex1 表格中執行每個INSERT 后,the _ex1_it 觸發器生成 DELETE語句的文本,它將撤銷 INSERT操作。The _ex1_ut觸發器生成 UPDATE語句,這語句將取消一個 UPDATE所產生的作用。trigger_ex1_dt觸發器生成一個語句,這語句將取消一個 DELETE所具有的作用。
要注意 quote()函數在這些觸發器中的使用。quote()函數在 SQLite中是標准的。它把它的參數轉換成一種適合被包含在 SQL 語句中的形式。數字值不改變。單個的 quotes 被加在字符串之前或之后,任何內在的單個quotes 都被逃逸。quote()函數被加入 SQLite是 為了執行撤銷和重做操作。
9、SQLite3 C/C++ 開發接口(API 函數)
Sqlite3是建立在sqlite2.8之上開發的,是為了支持UTF-16編碼、自定義的文本排序方法、對blobs字段建立索引。3.0版和2.x版的api非常相似,只不過前綴改成sqlite3。
SQLite使用了普通的 void* 類型來指向 UTF-16編碼的字符串. 客戶端使用過程中可以把 void*映射成適合他們的系統的任何數據類型。
SQLite 3.0 一共有83個API函數,此外還有一些數據結構和預定義(#defines). (完整的API介紹請參看另一份文檔.) 不過你們可以放心,這些接口使用起來不會像它的數量所暗示的那么復雜. 最簡單的程序仍然使用三個函數就可以完成: sqlite3_open(), sqlite3_exec(), 和 sqlite3_close()。
要是想更好的控制數據庫引擎的執行,可以使用提供的 sqlite3_prepare()函數把 SQL語句編譯成字節碼,然后在使用 sqlite3_step()函數來執行編譯后的字節碼。以sqlite3_column_開頭的一組API函數用來獲取查詢結果集中的信息. 許多接口函數都是成對出現的,同時有UTF-8和UTF-16兩個版本。 並且提供了一組函數用來執行用戶自定義的 SQL函數和文本排序函數。【附加體外話:其實有關數據庫的操作,java的api或是c/c++庫中都供普通操作數據庫的api或是方法。因為我對這幾門語言熟悉點,所以就順便說下,這語言之間的一些共性。】
9.1 如何打開關閉數據庫
typedef struct sqlite3 sqlite3;
int sqlite3_open(const char*, sqlite3**);
int sqlite3_open16(const void*, sqlite3**);
int sqlite3_close(sqlite3*);
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
int sqlite3_errcode(sqlite3*);
說明:sqlite3_open() 函數返回一個整數來標識狀態,而不是像第二版中一樣返回一個指向 sqlite3結構體的指針。 sqlite3_open() 和 sqlite3_open16() 的不同之處在於 sqlite3_open16() 使用UTF-16編碼(使用本地主機字節順序)傳遞數據庫文件名。 如果要連接新數據庫, sqlite3_open16() 將內部文本轉換為 UTF-16編碼, 反之 sqlite3_open() 將文本轉換為 UTF-8編碼。
打開或者創建數據庫的命令會被緩存,直到這個數據庫真正被調用的時候才會被執行。而且允許使用PRAGMA 聲明來設置如本地文本編碼或默認內存頁面大小等選項和參數。
sqlite3_errcode() 通常用來獲取最近調用的 API接口返回的錯誤代碼。sqlite3_errmsg() 則用來得到這些錯誤代碼所對應的文字說明。這些錯誤信息將以 UTF-8 的編碼返回,並且在下一次調用任何SQLite API 函數的時候被清除。sqlite3_errmsg16() 和 sqlite3_errmsg() 大體上相同,除了返回的錯誤信息將以 UTF-16 本機字節順序編碼。
SQLite3 的錯誤代碼相比SQLite2 沒有任何的改變,它們分別是:
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* SQL error or missing database */
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt()
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found
#define SQLITE_FULL 13 /* Insertion failed because database is full
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
9.2 執行 SQL 語句
typedef int (*sqlite_callback)(void*,int,char**, char**);
int sqlite3_exec(sqlite3*, const char * sql, sqlite_callback, void*, char**);
sqlite3_exec 函數依然像它在 SQLite2 中一樣承擔着很多的工作。 該函數的第二個參數中可以編譯和執行零個SQL 語句. 查詢的結果返回給回調函數。 更多地信息可以查看 API 參考。
typedef struct sqlite3_stmt sqlite3_stmt;
int sqlite3_prepare(sqlite3*, const char*, int, sqlite3_stmt**, const char**);
int sqlite3_prepare16(sqlite3*, const void*, int, sqlite3_stmt**, const void**);
int sqlite3_finalize(sqlite3_stmt*);
int sqlite3_reset(sqlite3_stmt*);
sqlite3_prepare 接口把一條 SQL 語句編譯成字節碼留給后面的執行函數sqlite3—_exec()。 使用該接口訪問數據庫是當前比較好的的一種方法。
sqlite3_prepare() 處理的SQL語句應該是UTF-8編碼的。而sqlite3_prepare16() 則要求是UTF-16編碼的。輸入的參數中只有第一個 SQL 語句會被編譯。 第四個參數則用來指向輸入參數中下一個需要編譯的 SQL 語句存放的 SQLite statement 對象的指針, 任何時候如果調用 sqlite3_finalize() 將銷毀一個准備好的 SQL 聲明。 在數據庫關閉之前,所有准備好的聲明都必須被釋放銷毀。 sqlite3_reset() 函數用來重置一個 SQL 聲明的狀態,使得它可以被再次執行。
SQL 聲明可以包含一些型如"?" 或 "?nnn" 或 ":aaa"的標記, 其中"nnn" 是一個整數,"aaa" 是一個字符串。這些標記代表一些不確定的字符值(或者說是通配符),可以在后面用 sqlite3_bind 接口來填充這些值。每一個通配符都被分配了一個編號(由它在 SQL 聲明中的位置決定,從 1 開始),此外也可以用 "nnn" 來表示 "?nnn" 這種情況。允許相同的通配符在同一個 SQL 聲明中出現多次, 在這種情況下所有相同的通配符都會被替換成相同的值。沒有被綁定的通配符將自動取 NULL 值。
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, long long int);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
以上是 sqlite3_bind 所包含的全部接口,它們是用來給 SQL 聲明中的通配符賦值的。沒有綁定的通配符則被認為是空值。綁定上的值不會被 sqlite3_reset()函數重置。但是在調用了 sqlite3_reset()之后所有的通配符都可以被重新賦值。
在 SQL 聲明准備好之后(其中綁定的步驟是可選的), 需要調用以下的方法來執行:
int sqlite3_step(sqlite3_stmt*);
如果 SQL 返回了一個單行結果集,sqlite3_step() 函數將返回 SQLITE_ROW , 如果 SQL 語句執行成功或者正常將返回SQLITE_DONE , 否則將返回錯誤代碼. 如果不能打開數據庫文件則會返回 SQLITE_BUSY . 如果函數的返回值是SQLITE_ROW, 那么下邊的這些方法可以用來獲得記錄集行中的數據:
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
nt sqlite3_column_count(sqlite3_stmt*);
const char *sqlite3_column_decltype(sqlite3_stmt *, int iCol);
const void *sqlite3_column_decltype16(sqlite3_stmt *, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
long long int sqlite3_column_int64(sqlite3_stmt*, int iCol);
const char *sqlite3_column_name(sqlite3_stmt*, int iCol);
const void *sqlite3_column_name16(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_column_count()函數返回結果集中包含的列數。sqlite3_column_count() 可以在執行了 sqlite3_prepare()之后的任何時刻調用。sqlite3_data_count()除了必需要在 sqlite3_step()之后調用之外,其他跟 sqlite3_column_count() 大同小異。如果調用 sqlite3_step() 返回值是 SQLITE_DONE 或者一個錯誤代碼, 則此時調用 sqlite3_data_count() 將返回 0 ,然而 sqlite3_column_count() 仍然會返回結果集中包含的列數。返回的記錄集通過使用其它的幾個 sqlite3_column_***() 函數來提取, 所有的這些函數都把列的編號作為第二個參數。列編號從左到右以零起始。
sqlite3_column_type()函數返回第 N 列的值的數據類型。 具體的返回值如下:
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
#define SQLITE_TEXT 3
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
sqlite3_column_decltype() 則用來返回該列在 CREATE TABLE 語句中聲明的類型。 它可以用在當返回類型是空字符串的時候。 sqlite3_column_name() 返回第 N 列的字段名。 sqlite3_column_bytes() 用來返回 UTF-8 編碼的 BLOBs 列的字節數或者 TEXT 字符串的字節數。 sqlite3_column_bytes16() 對於 BLOBs 列返回同樣的結果,但是對於 TEXT 字符串則按 UTF-16 的編碼來計算字節數。 sqlite3_column_blob() 返回 BLOB 數據。 sqlite3_column_text() 返回 UTF-8 編碼的 TEXT 數據。 sqlite3_column_text16() 返回 UTF-16 編碼的 TEXT 數據。 sqlite3_column_int() 以本地主機的整數格式返回一個整數值。 sqlite3_column_int64() 返回一個 64 位的整數。 最后, sqlite3_column_double() 返回浮點數。
10、SQLite 常見問題解答
(1)、如何建立自動增長的字段:可以在字段上聲明為INTEGER PRIMARY KEY AUTOINCREATE。
(2)、SQLite 支持何種數據類型:參見 http://www.sqlite.org/datatype3.html。
(3)、Sqlite允許一個列中插入任何類型的字段,(前面我們說過sqlite是種弱類型,不想其他的語言,如java),但任何類型的字段會被自動轉換該列所需的類型,轉換不了的則按任何類型對應的類型插入。(這就是我在前面說的類型親和性)有一種除外,就是標志為INTEGER PRIMARY KEY 的列只能存儲 64位整數, 當向這種列中插數據除整數以外的數據時,將會產生錯誤。
(4)、SQLite 不允許在同一個表不同的兩行上使用 0 和0.0 作主鍵,因為這兩者sqlite認為是相等,既然相等就是不唯一。
(5)、多個進程可同時打開同一個數據庫。多個進程可以同時進行 SELECT (讀)操作,但在任一時刻,只能有一個進程對數據庫進行更改(寫)。看到這么一句話這樣說的,我覺得很有借鑒性,所以摘入到此,雖不是原話,大致意思是這樣的, 對於網絡文件,文件鎖的實現有好多 Bug,是靠不住的。如果他們說的是對的, 那么在兩台或多台 Windows機器間共享數據庫可能會引起不期望的問題(關系數據庫兩外算)。SQLite允許多個進程同時打開一個數據庫, 同時讀一個數據庫。當有任何進程想要寫時,它必須在更新過程中鎖住數據庫文件。 但那通常只是幾毫秒的時間。其它進程只需等待寫進程干完活結束。 當SQLite 試圖訪問一個被其它進程鎖住的文件時,缺省的行為是返回 SQLITE_BUSY。(sqlite3是線程安全的)
(6)、在 SQLite 數據庫中如何列出所有的表和索引:.tables和.schema和數據字典sqlite_master; 字典結構: type TEXT, name TEXT, tbl_name TEXT, rootpage INTEGER, sql TEXT 。
(7)、SQLite 數據庫有已知的大小限制嗎? 見 limits.html 。
(8)、在 SQLite 中,如何在一個表上添加或刪除一列?Sqlite沒有提供完整的alter支持,可以使用它來在表的末尾增加一列,可更改表的名稱。 如果需要對表結構做更復雜的改變,則必須重新建表。 重建時可以先將已存在的數據放到一個臨時表中,刪除原表, 創建新表,然后將數據從臨時表中復制回來。 如,假設有一個 t1 表,其中有 "a", "b", "c" 三列, 如果要刪除列 c ,以下過程描述如何做:
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b); 臨時表
INSERT INTO t1_backup SELECT a,b FROM t1; 臨時表拷貝表t1數據
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
END TRANSACTION;
COMMIT;