天天看點

SQLite使用小結

一、SQLite簡介  

  SQLite是一款輕型的資料庫,是遵守ACID的關聯式資料庫管理系統,它的設計目标是嵌入式的,而且目前已經在很多嵌入式産品中使用了它,它占用資源非常的低,在嵌入式裝置中,可能隻需要幾百K的記憶體就夠了。它能夠支援Windows/Linux/Unix等等主流的作業系統,同時能夠跟很多程式語言相結合,比如Tcl、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源世界著名的資料庫管理系統來講,它的處理速度比他們都快。

  SQLite雖然很小巧,但是支援的SQL語句不會遜色于其他開源資料庫,它支援的SQL包括:

  ATTACH DATABASE

  BEGIN TRANSACTION

  comment

  COMMIT TRANSACTION

  COPY

  CREATE INDEX

  CREATE TABLE

  CREATE TRIGGER

  CREATE VIEW

  DELETE

  DETACH DATABASE

  DROP INDEX

  DROP TABLE

  DROP TRIGGER

  DROP VIEW

  END TRANSACTION

  EXPLAIN

  expression

  INSERT

  ON CONFLICT clause

  PRAGMA

  REPLACE

  ROLLBACK TRANSACTION

  SELECT

  UPDATE

  同時它還支援事務處理功能等等。也有人說它象Microsoft的Access,有時候真的覺得有點象,但是事實上它們差別很大。比如SQLite 支援跨平台,操作簡單,能夠使用很多語言直接建立資料庫,而不象Access一樣需要Office的支援。如果你是個很小型的應用,或者你想做嵌入式開發,沒有合适的資料庫系統,那麼現在你可以考慮使用SQLite。目前它的最新版本是 3.2.2,它的官方網站是:http://www.sqlite.org或者http://www.sqlite.com.cn,能在上面獲得源代碼和文檔。同時因為資料庫結構簡單,系統源代碼也不是很多,也适合想研究資料庫系統開發的專業人士

  下面是通路SQLite官方網站: http://www.sqlite.org/ 時第一眼看到關于SQLite的特性.

  1. ACID事務

  2. 零配置 – 無需安裝和管理配置

  3. 儲存在單一磁盤檔案中的一個完整的資料庫

  4. 資料庫檔案可以在不同位元組順序的機器間自由的共享

  5. 支援資料庫大小至2TB

  6. 足夠小, 大緻3萬行C代碼, 250K

  7. 比一些流行的資料庫在大部分普通資料庫操作要快

  8. 簡單, 輕松的API

  9. 包含TCL綁定, 同時通過Wrapper支援其他語言的綁定

  10. 良好注釋的源代碼, 并且有着90%以上的測試覆寫率

  11. 獨立: 沒有額外依賴

  12. Source完全的Open, 你可以用于任何用途, 包括出售它

  13. 支援多種開發語言,C, PHP, Perl, Java, ASP.NET,Python

  2、SQLite類型

  SQLite的資料類型

  首先你會接觸到一個讓你驚訝的名詞: Typelessness(無類型). 對! SQLite是無類型的. 這意味着你可以儲存任何類型的資料到你所想要儲存的任何表的任何列中, 無論這列聲明的資料類型是什麼(隻有在一種情況下不是, 稍後解釋). 對于SQLite來說對字段不指定類型是完全有效的. 如:

  Create Table ex1(a, b, c);

  誠然SQLite允許忽略資料類型, 但是仍然建議在你的Create Table語句中指定資料類型. 因為資料類型對于你和其他的程式員交流, 或者你準備換掉你的資料庫引擎. SQLite支援常見的資料類型, 如:

  CREATE TABLE ex2(

  a VARCHAR(10),

  b NVARCHAR(15),

  c TEXT,

  d INTEGER,

  e FLOAT,

  f BOOLEAN,

  g CLOB,

  h BLOB,

  i TIMESTAMP,

  j NUMERIC(10,5)

  k VARYING CHARACTER (24),

  l NATIONAL VARYING CHARACTER(16)

  );

  前面提到在某種情況下, SQLite的字段并不是無類型的. 即在字段類型為”Integer Primary Key”時.

二、SQLite的簡單使用

SQLite可以到官方站點下載下傳http://www.sqlite.org/download.html

包括:Linux,Mac OS X, Windows下的已編譯檔案以及源代碼、幫助文檔。windows版的下載下傳位址是:http://www.sqlite.org/sqlite-3_6_23_1.zip,下載下傳後解壓就可以了。這個檔案是工作在指令行下的。輕按兩下它,就直接進入指令行了。

打開之後是這樣顯示的:

SQLite version 3.6.23.1

Enter ".help" for instructions

Enter SQL statements terminated with a ";"

sqlite>

1、建立資料庫

按理說第一步是建立一個資料庫,我是學電子的,對計算機不了解,是以我不知道mysql是如何存儲資料庫的。但sqlite将一個資料庫存儲為一個檔案。我們先進下cmd,關掉原來的sqlite3。

在指令提示符下:

sqlite3 newsql.db

然後就會自動跳到sqlite>指令提示符下。我記得在linux下用時候會在目前目錄下出現newsql.db檔案。但在我所用版本的windows下沒有出現。然後我做了些嘗試得到如下結果:

sqlite3 newsql.db

.quit

注意:.quit是在sqlite提示符下輸入的,代表退出。看目錄下還是沒有出現資料庫檔案。

sqlite3 newsql.db

;

.quit

出現了newsql.db檔案。冒号加回車,在sqlite中,代表執行一條語句的意思,雖然我隻輸入了一個冒号加回車,沒有輸入任何的語句,但結果已是不同。

2、建立一個表

create table mytable(entry1 varchar(10),entry2 int);

不要忘了加冒号。冒号代表一條語句輸入完畢。

mytable是我建立的表名。create 和table都是系統關鍵字。entry1,entry2是兩個表項。

varchar(10) int是類型。根據我讀到的内容,sqlite是不區分類型,但是我們還是要在建立表時,給他一個類型,以便于将這些代碼移植到其他的資料庫裡面時更加的友善。

3、向表中插入一條記錄

insert into mytable values("hello world",10);

插入完了之後才發現是不是超出定義的大小了?我定義的entry1項是varchar(10)型的,說實在的,我不知這個類型确切來講是什麼意思,我猜應該是10個字元的字元串數組吧。如果那樣的話我是一定超出了。但既然sqlite是不區分類型的,我想應該沒有問題吧。于是我急于看看是不是這樣...

4、查詢表中内容

select * from mytable;

執行這條語句,會列出mytable中的所有内容。

結果為:

sqlite> select * from mytable;

hello world|10

可見還是都插入進去了。

sqlite> insert into mytable values("goodbye cruel world",20);

sqlite> select * from mytable;

hello world|10

goodbye cruel world|20

也就是說,第一個條目的字元串完全不受限制。

5、sqlite3 newsql.db的規則

我們現在退出,然後重新打開資料庫:

sqlite> .quit

F:/sqlite>sqlite3 newsql.db

SQLite version 3.6.23.1

Enter ".help" for instructions

Enter SQL statements terminated with a ";"

sqlite> select * from mytable;

hello world|10

goodbye cruel world|20

可見sqlite3 newsql.db這個指令規則為:打開名為newsql.db這個資料庫,如果不存在則建立一個。

6、查詢一個資料庫中所有的表名

sqlite資料庫中有一個系統建立的表,名為sqlite_master,查詢這個表可以得到所有的表。

sqlite> create table my2ndtable(theonlyentry int);

sqlite> insert into my2ndtable values(30);

sqlite> select * from sqlite_master;

table|mytable|mytable|2|CREATE TABLE mytable(entry1 varchar(10),entry2 int)

table|my2ndtable|my2ndtable|3|CREATE TABLE my2ndtable(theonlyentry int)

對于這個表的定義,官方網站的FAQ中給出如下:

CREATE TABLE sqlite_master ( type TEXT, name TEXT, tbl_name TEXT, rootpage INTEGER, sql TEXT );第一個字段類型顯然會一直是table,第二個字段是名稱分别是mytable和my2ndtable,見上面的結果。第三個字段表名,沒弄懂是什麼意,想必是所在的表的名字,但是一個表的名字和所在的表名不是一樣的嗎?第四個字段rootpage,我也不知指什麼,這個系統的學過資料庫的人應該能知道,有路過的還望告之。第五個字段是建立表的使用的sql語句吧。

7、sqlite的輸出模式

 預設的輸出格式是“清單”。在清單模式下,每條查詢結果記錄被寫在一行中并且每列之間以一個字元串分割符隔開。預設的分隔符是一個管道符号(“|”)。清單符号在當你輸出查詢結果到另外一個符号處理的程式(如AWK)中去是尤為有用。

sqlite> .mode list

sqlite> select * from mytable;

hello world|10

goodbye cruel world|20

sqlite>

這是正常的模式。

sqlite> .mode csv

sqlite> select * from mytable;

"hello world",10

"goodbye cruel world",20

變化是什麼?字元串被加上了引号。

sqlite> .mode column

sqlite> select * from mytable;

hello world  10

goodbye cru  20

哎呀,第二個字元串被截斷了。

.mode MODE ?TABLE?__  Set output mode where MODE is one of:

____________  csv___ Comma-separated values

____________  column_  Left-aligned columns._ (See .width)

____________  html__  HTML <table> code

____________  insert_  SQL insert statements for TABLE

____________  line__  One value per line

____________  list__  Values delimited by .separator string

____________  tabs__  Tab-separated values

____________  tcl___ TCL list elements

這些來自.help指令的輸出結果。

sqlite> .mode html

sqlite> select * from mytable;

<TR><TD>hello world</TD>

<TD>10</TD>

</TR>

<TR><TD>goodbye cruel world</TD>

<TD>20</TD>

</TR>

.mode html是一種較新的輸出方法。

另外,我們也可以把輸出結果輸出到檔案:

sqlite> .output output.txt

sqlite> select * from mytable;

sqlite> .exit

F:/sqlite>type output.txt

hello world|10

goodbye cruel world|20

8、檢視資料庫中所有的表

sqlite> .tables

my2ndtable  mytable

9、檢視所有的表的建立語句

sqlite> .schema

CREATE TABLE my2ndtable(theonlyentry int);

CREATE TABLE mytable(entry1 varchar(10),entry2 int);

sqlite> .schema mytable

CREATE TABLE mytable(entry1 varchar(10),entry2 int);

10、資料庫導出和導入

我們可以利用這個功能做一個簡單的備份,或是說建立一個同樣的資料庫。

第一步,把資料庫倒出來:

cmd指令提示符下:

F:/sqlite>sqlite3 newsql.db ".dump" >a.sql

此語句将資料庫導出成a.sql資料庫語句檔案,執行這個檔案就可以建立一個一模一樣資料庫:

F:/sqlite>sqlite3 copied.db

SQLite version 3.6.23.1

Enter ".help" for instructions

Enter SQL statements terminated with a ";"

sqlite> select * from mytable;

hello world|10

goodbye cruel world|20

11、删除記錄

delete from mytable where entry2=10;

可以删掉mytable中所有entry2項為10的條目。

注意:不是delete * from mytable,而delete from mytable.沒有*.

三、SQLite3 C/C++ 開發接口簡介(API函數)

SQLite3是SQLite一個全新的版本,它雖然是在SQLite 2.8.13的代碼基礎之上開發的,但是使用了和之前的版本不相容的資料庫格式和API. SQLite3是為了滿足以下的需求而開發的:

  • 支援UTF-16編碼.
  • 使用者自定義的文本排序方法.
  • 可以對BLOBs字段建立索引.

是以為了支援這些特性我改變了資料庫的格式,建立了一個與之前版本不相容的3.0版. 至于其他的相容性的改變,例如全新的API等等,都将在理論介紹之後向你說明,這樣可以使你最快的一次性擺脫相容性問題.

3.0版的和2.X版的API非常相似,但是有一些重要的改變需要注意. 所有API接口函數和資料結構的字首都由"sqlite_"改為了"sqlite3_". 這是為了避免同時使用SQLite 2.X和SQLite 3.0這兩個版本的時候發生連結沖突.

由于對于C語言應該用什麼資料類型來存放UTF-16編碼的字元串并沒有一緻的規範. 是以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函數和文本排序函數.

2.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 */      

2.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 參考.

在SQLite3裡,sqlite3_exec一般是被準備SQL語句接口封裝起來使用的.

       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_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);

       int 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_***() 函數來提取, 所有的這些函數都把列的編号作為第二個參數. 列編号從左到右以零起始. 請注意它和之前那些從1起始的參數的不同.

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() 傳回浮點數.

不一定非要按照sqlite3_column_type()接口傳回的資料類型來擷取資料. 資料類型不同時軟體将自動轉換.

2.3核心對象和接口

SQL資料庫引擎的最主要任務是解析SQL語句。為了達成這個目的,開發者需要了解兩個對象:

* 資料庫連接配接對象:sqlite3

* 預處理語句對象:sqlite3_stmt

嚴格來講,預處理語句對象并不是必須的,因為能夠使用sqlite_exec或者sqlite3_get_table這些便于使用的封裝接口,而這些接口封裝并隐藏了預處理語句對象。盡管如此,對預處理對象的了解有助于我們更充分的使用SQLite。

資料庫連接配接對象和預處理對象是由下列的一組C/C++接口調用操縱的:

* sqlite3_open()

* sqlite3_prepare()

* sqlite3_step()

* sqlite3_column()

* sqlite3_finalize()

* sqlite3_close()

這6個C/C++接口例程和上述的兩個對象構成了SQLite的核心功能。開發者對于它們的了解能夠更好的使用SQLite。

注意,這個接口例程清單更多是概念上的意義而不是實際的接口。許多這些接口都出現在各個版本之中。例如,上述清單中的sqlite3_open() 例程實際上有三個不同的接口以略微不同的方式實作相同的功能:slqite3_open(),sqlite3_open16()和 sqlite3_open_v2()。清單中的實際上并不存在sqlite3_column()這個接口。顯示在清單中的 “sqlite3_column()”僅僅是一個占位,表示一整套用于從表中查詢出各種資料類型的列記錄接口。

這裡說明下核心接口的主要功能:

* sqlite3_open() 該接口打開與一個SQLite資料庫檔案的連接配接并傳回一個資料庫連接配接對象。這通常是應用程式調用的第一個SQLite API接口而且也是調用其他SQLite API接口前需要調用的接口。許多SQLite接口需要一個指向資料庫連接配接對象的指針作為它們的第一個參數,因而這些接口也可以了解成是資料庫連接配接對象的操作接口。該接口就是建立了這樣一個資料庫連接配接對象。

* sqlite3_prepare() 該接口把一個SQL語句文本轉換成一個預處理語句對象并傳回一個指向該對象的指針。這個接口需要一個由先前調用sqlite3_open()傳回的資料庫連接配接對象指針以及一個預處理的SQL語句文本字元串為參數。這個API并不實際解析SQL語句,僅僅是為後續的解析而對SQL語句進行的預處理。

注意新的應用中不建議使用sqlite3_prepare(),而應該使用另一個接口sqlite3_prepare_v2()。

* sqlite3_step() 該接口用于解析一個由先前通過sqlite3_prepare()接口建立的預處理語句,直至傳回第一列結果為止。通過再次調用 sqlite3_step()可以傳回下一列的結果,繼續不斷地調用sqlite3_step()直至整個語句完成為止。對于那些并不傳回結果的語句(例如:INSERT,UPDATE,DELETE語句)一次調用sqlite3_step()就完成了語句的處理。

* sqlite3_column() 該接口傳回一個由sqlite3_step()解析的預處理語句結果集中目前行的某一列資料。每次執行sqlite3_step()都傳回一個新的結果集中的一行。可以多次調用sqlite3_column()接口傳回那一行中所有列的資料。就像上面所說的那樣,SQLite API中并沒有sqlite3_column()這樣的接口。取而代之的是一組用于從結果集中查詢出各個列項各種資料類型資料的函數接口。在這組函數接口中,有些接口傳回結果集的大小,有些傳回結果集的列數。

*sqlite3_column_blob()

*sqlite3_column_bytes()

*sqlite3_column_bytes16()

*sqlite3_column_count()

*sqlite3_column_double()

*sqlite3_column_int()

*sqlite3_column_int64()

*sqlite3_column_text()

*sqlite3_column_text16()

*sqlite3_column_type()

*sqlite3_column_value()

* sqlite3_finalize() 該接口銷毀之前調用sqlite3_prepare()建立的預處理語句。每一個預處理語句都必須調用這個接口進行銷毀以避免記憶體洩

漏。

* sqlite3_close() 該接口關閉一個由之前調用sqlite3_open()建立的資料庫連接配接。所有與該連接配接相關的預處理語句都必須在關閉連接配接之前銷毀。

2.4擴充SQLite

SQLite包含一些可用于擴充其功能的一些其他接口,這些接口包括:

* sqlite3_create_collation()

* sqlite3_create_function()

* sqlite3_create_module()

sqlite3_create_collation()接口用于為索引文本建立新的對照序列。sqlite3_create_module()接口用于注冊新的續表實作接口。

sqlite3_create_function()接口建立新的SQL函數-即可以是單一的也可以是組合的接口。新的函數實作通常利用下列的輔助接口:

* sqlite3_aggregate_context()

* sqlite3_result()

* sqlite3_user_data()

* sqlite3_value()

SQLite中所有内建的SQL函數接口也是通過這些相同的接口實作的。檢視SQLite源代碼,尤其是date.c和func.c兩個檔案就有許多這方面的例子。

四、在VC下使用SQLite

#include "../sqlite3_lib/sqlite3.h"

#pragma comment(lib, "../sqlite3_lib/sqlite3.lib")

static int _sql_callback(void * notused, int argc, char ** argv, char ** szColName)

{

    int i;

    for ( i=0; i < argc; i++ )

    {

        printf( "%s = %s/n", szColName[i], argv[i] == 0 ? "NUL" : argv[i] );

    }

    return 0;

}

int main(int argc, char * argv[])

{

    const char * sSQL1 = "create table users(userid varchar(20) PRIMARY KEY, age int, birthday datetime);";

    const char * sSQL2 = "insert into users values('wang',20,'1989-5-4');";

    const char * sSQL3 = "select * from users;";

    sqlite3 * db = 0;

    char * pErrMsg = 0;

    int ret = 0;

    // 連接配接資料庫

    ret = sqlite3_open("./test.db", &db);

    if ( ret != SQLITE_OK )

    {

        fprintf(stderr, "無法打開資料庫: %s", sqlite3_errmsg(db));

        return(1);

    }

    printf("資料庫連接配接成功!/n");

    // 執行建表SQL

    sqlite3_exec( db, sSQL1, 0, 0, &pErrMsg );

    if ( ret != SQLITE_OK )

    {

        fprintf(stderr, "SQL error: %s/n", pErrMsg);

        sqlite3_free(pErrMsg);

    }

    // 執行插入記錄SQL

    sqlite3_exec( db, sSQL2, 0, 0, &pErrMsg);

    // 查詢資料表

    sqlite3_exec( db, sSQL3, _sql_callback, 0, &pErrMsg);

    // 關閉資料庫

    sqlite3_close(db);

    db = 0;

    return 0;

}

使用事務

    在上面的例子中,我們向資料庫裡插入了10條資料,然後再從資料庫裡讀出來。細心的你不知道有沒有發現,在執行Insert的時候

,并沒有使用同一個事 務。在很多情況下,我們需要使用事務來保證對資料庫操作的原子性。Sqlite是支援事務的,而且對事務的使用非常簡單:

使用sql語句”begin;” 表示事務開始,”rollback;”表示事務的復原,”commit;”表示事務的送出。下面我們對上面例子中的代碼作一下修改,

給Insert操作添 加事務支援:      
//... ...
      

bool is_succed = true; sqlite3_exec(conn, "begin;", 0, 0, 0);  //

開啟事務 //添加10條記錄 for (int i = 0; i < 10; i++) {     // 執行SQL     sprintf(sql, "INSERT INTO [test_for_cpp] ([id], [name], [age]) /         VALUES (%d, '%s', %d)", i, "JGood", i);     if (SQLITE_OK != sqlite3_exec(conn, sql, 0, 0, &err_msg))     {         is_succed = false;         break;     } } if (is_succed)     sqlite3_exec(conn, "commit;", 0, 0, 0);  // 送出事務 else     sqlite3_exec(conn, "rollback;", 0, 0, 0);  // 復原事務 //... ...

使用sql參數

    基本上,使用sqlite3_open, sqlite3_close, sqlite3_exec這三個函數,

可以完成大大部分的工作。但還不完善。上面的例子中,都是直接以sql語句的形式來操作資料庫,這樣很容易被注入。是以有必要使用sql參數。      
sqlite3_prepare      
sqlite3_bind_*      
sqlite3_step      
sqlite3_column_*      
struct sqlite3_stmt      
sqlite3_finalize      
    sqlite3_prepare用來編譯sql語句。sql語句被執行之前,

必須先編譯成位元組碼。sqlite3_stmt是一個結構體,表示sql語句 編譯後的位元組碼。sqlite3_step用來執行編譯後的sql語句。      
sqlite3_bind_*用于将sql參數綁定到sql語句。 sqlite3_column_*用于從查詢的結果中擷取資料。sqlite3_finalize用來釋放sqlite3_stmt對象。代碼最能說明函 數的功能,      
下面就用一個例子來示範吧~~      
// ----------------------------------------------

// http://blog.csdn.net/JGood      
// sqlite3_prepare, sqlite3_bind_*, sqlite3_step, sqlite3_column_*, sqlite3_column_type

// sqlite3_stmt, sqlite3_finalize, sqlite3_reset

// 查詢

// ----------------------------------------------

sqlite3 *conn = NULL;

sqlite3_stmt *stmt = NULL;

const char *err_msg = NULL;

// 列資料類型

char col_types[][10] = { "", "Integer", "Float", "Text", "Blob", "NULL" };



sqlite3_open("test.db", &conn);

sqlite3_prepare(conn, "SELECT * FROM [test_for_cpp] WHERE [id]>?", -1, &stmt, &err_msg);

sqlite3_bind_int(stmt, 1, 5);



while (SQLITE_ROW == sqlite3_step(stmt))

{

    int col_count = sqlite3_column_count(stmt); // 結果集中列的數量



    const char *col_0_name = sqlite3_column_name(stmt, 0); // 擷取列名

    int id = sqlite3_column_int(stmt, 0);

    int id_type = sqlite3_column_type(stmt, 0); // 擷取列資料類型



    const char *col_2_name = sqlite3_column_name(stmt, 2);

    int age = sqlite3_column_int(stmt, 2);

    int age_type = sqlite3_column_type(stmt, 2);



    const char *col_1_name = sqlite3_column_name(stmt, 1);

    char name[80];

    strncpy(name, (const char *)sqlite3_column_text(stmt, 1), 80);

    int name_type = sqlite3_column_type(stmt, 1);



    // 列印結果

    printf("col_count: %d, %s = %d(%s), %s = %s(%s), %s = %d(%s)/n",

        col_count, col_0_name, id, col_types[id_type], col_2_name, name,

        col_types[name_type], col_1_name, age, col_types[age_type]);

}



sqlite3_finalize(stmt); // 釋放sqlite3_stmt 

sqlite3_close(conn);      
這段代碼查詢id号大于5的所有記錄. 
      
其他函數      
 在上面的例子中,還使用了其他的一些函數,      
如:sqlite3_column_count用于擷取結果集中列的數 量;sqlite3_column_name用于擷取列的名稱;      
sqlite3_column_type用于擷取列的資料類 型;sqlite3_errcode用于擷取最近一次操作出錯的錯誤代碼;      
sqlite3_errmsg用于擷取最近一次操作出錯的錯誤說明。 sqlite的api中還有很多的函數,有了上面的基礎,      

相信你通過查詢官方的文檔,能迅速掌握本文未介紹的api。

五、資料庫管理工具

sqlite 管理工具 Sqlite Developer

Sqlite Developer是SharpPlus出品的一款強大資料庫管理軟體。支援對sqlite3資料庫的管理。

下載下傳:http://dl.pconline.com.cn/download/60827.html

 Sqlite Developer 注冊碼:http://download.csdn.net/source/2755962

常見問題:

1、  建立資料

如果不往資料庫裡面添加任何的表,這個資料庫等于沒有建立,不會在硬碟上産生任何檔案,如果資料庫已經存在,則會打開這個資料庫。

2、  如何通過sqlite3.dll與sqlite3.def生成sqlite3.lib檔案

LIB /DEF:sqlite3.def /machine:IX86

3、  如何查詢目前的編碼的編碼格式

pragma  encoding;

4、  如果删除了大量資料,而又想縮小資料庫檔案占用的空間,執行 VACUUM 指令

vacuum;

5、  sqlite3_open打開一個資料庫時,如果資料庫不存在就會新生成一個資料庫檔案。如果接着執行其他查詢語句就會失敗,比如sqlite3_prepare,程式設計中出現明明指定了資料庫而且裡面也有資料,為什麼查詢失敗了,主要是資料庫名路徑不對引起的。一般的做法是先檢查資料庫檔案是否存在,如果存在就使用sqlite3_open打開資料庫;否則建立一個新的資料庫。

6、  如何建立自動增長字段

聲明為 INTEGER PRIMARY KEY 的列将會自動增長。

7、SQLite3支援何種資料類型?

NULL

INTEGER

REAL

TEXT

BLOB

但實際上,sqlite3也接受如下的資料類型:

smallint 16 位元的整數。

interger 32 位元的整數。

decimal(p,s) p 精确值和 s 大小的十進位整數,精确值p是指全部有幾個數(digits)大小值 ,s是指小數點後有幾位數。如果沒有特别指定,則系統會設為 p=5; s=0 。

float 32位元的實數。

double 64位元的實數。

char(n) n 長度的字串,n不能超過 254。

varchar(n) 長度不固定且其最大長度為 n 的字串,n不能超過 4000。

graphic(n) 和 char(n) 一樣,不過其機關是兩個字元 double-bytes, n不能超過127。 這個形态是為了支援兩個字元長度的字型,例如中文字。

vargraphic(n) 可變長度且其最大長度為 n 的雙字元字串,n不能超過 2000。

date 包含了 年份、月份、日期。

time 包含了 小時、分鐘、秒。

timestamp 包含了 年、月、日、時、分、秒、千分之一秒。

8、SQLite允許向一個integer型字段中插入字元串

這是一個特性,而不是一個bug。SQLite不強制資料類型限制。任何資料都可以插入任何列。你可以向一個整型列中插入任意長度的字元串,向布爾型列中插入浮點數,或者向字元型列中插入日期型值。 在 CREATE TABLE 中所指定的資料類型不會限制在該列中插入任何資料。任何列均可接受任意長度的字元串(隻有一種情況除外: 标志為INTEGER PRIMARY KEY的列隻能存儲64位整數,當向這種列中插資料除整數以外的資料時,将會産生錯誤。

但SQLite确實使用聲明的列類型來訓示你所期望的格式。是以,例如你向一個整型列中插入字元串時,SQLite會試圖将該字元串轉換成一個整數。如果可以轉換,它将插入該整數;否則,将插入字元串。這種特性有時被稱為 類型或列親和性(type or column affinity).

9、為什麼SQLite不允許在同一個表不同的兩行上使用0和0.0作主鍵?

主鍵必須是數值類型,将主鍵改為TEXT型将不起作用。

每一行必須有一個唯一的主鍵。對于一個數值型列, SQLite認為 '0' 和 '0.0' 是相同的, 因為他們在作為整數比較時是相等的(參見上一問題)。 是以,這樣值就不唯一了。

10、多個應用程式或一個應用程式的多個執行個體可以同時通路同一個資料庫檔案嗎?

多個程序可同時打開同一個資料庫。多個程序可以同時進行SELECT 操作,但在任一時刻,隻能有一個程序對資料庫進行更改。

SQLite 使用讀、寫鎖控制對資料庫的通路。(在Win95/98/ME等不支援讀、寫鎖的系統下,使用一個機率性的模拟來代替。)但使用時要注意:如果資料庫檔案存放于一個NFS檔案系統上,這種鎖機制可能不能正常工作。 這是因為 fcntl() 檔案鎖在很多NFS上沒有正确的實作。在可能有多個程序同時通路資料庫的時候,應該避免将資料庫檔案放到NFS上。在Windows上,Microsoft的文檔中說:如果使用 FAT 檔案系統而沒有運作 share.exe 守護程序,那麼鎖可能是不能正常使用的。那些在Windows上有很多經驗的人告訴我:對于網絡檔案,檔案鎖的實作有好多Bug,是靠不住的。如果他們說的是對的,那麼在兩台或多台Windows機器間共享資料庫可能會引起不期望的問題。

我們意識到,沒有其它嵌入式的 SQL 資料庫引擎能象 SQLite 這樣處理如此多的并發。SQLite允許多個程序同時打開一個資料庫,同時讀一個資料庫。當有任何程序想要寫時,它必須在更新過程中鎖住資料庫檔案。但那通常隻是幾毫秒的時間。其它程序隻需等待寫程序幹完活結束。典型地,其它嵌入式的SQL資料庫引擎同時隻允許一個程序連接配接到資料庫。

但是,Client/Server資料庫引擎(如 PostgreSQL, MySQL, 或 Oracle)通常支援更進階别的并發,并且允許多個程序同時寫同一個資料庫。這種機制在Client/Server結構的資料庫上是可能的,因為總是有一個單一的伺服器程序很好地控制、協調對資料庫的通路。如果你的應用程式需要很多的并發,那麼你應該考慮使用一個Client/Server 結構的資料庫。但經驗表明,很多應用程式需要的并發,往往比其設計者所想象的少得多。

當SQLite試圖通路一個被其它程序鎖住的檔案時,預設的行為是傳回 SQLITE_BUSY。 可以在C代碼中使用 sqlite3_busy_handler() 或 sqlite3_busy_timeout() API 函數調整這一行為。

11、SQLite線程安全嗎?

線程是魔鬼(Threads are evil)。 避免使用它們。

SQLite 是線程安全的。由于很多使用者會忽略我們在上一段中給出的建議, 我們做出了這種讓步。但是,為了達到線程安全,SQLite在編譯時必須将 SQLITE_THREADSAFE 預處理宏置為1。在Windows和Linux上,已編譯的好的二進制發行版中都是這樣設定的。如果不确定你所使用的庫是否是線程安全的,可以調用 sqlite3_threadsafe() 接口找出。

12、在SQLite資料庫中如何列出所有的表和索引?

如果你運作 sqlite3 指令行來通路你的資料庫,可以鍵入 “.tables”來獲得所有表的清單。或者,你可以輸入 “.schema” 來看整個資料庫模式,包括所有的表的索引。 輸入這些指令,後面跟一個LIKE模式比對可以限制顯示的表。

13、SQLite資料庫有已知的大小限制嗎?

在 Windows 和 Unix 下,版本 2.7.4的 SQLite 可以達到 2的41次方位元組 (2T 位元組)。老版本的為 2的31 次方位元組(2G 位元組)。

SQLite 版本 2.8 限制一個記錄的容量為 1M。SQLite 版本 3.0 則對單個記錄容量沒有限制。

表名、索引表名、視圖名、觸發器名和字段名沒有長度限制。但 SQL 函數的名稱 (由 sqlite3_create_function() API 函數建立) 不得超過 255 個字元。

14、在SQLite中,VARCHAR字段最長是多少?

SQLite 不強制 VARCHAR 的長度。 你可以在 SQLITE 中聲明一個 VARCHAR(10),SQLite還是可以很高興地允許你放入500個字元。 并且這500個字元是原封不動的,它永遠不會被截斷。

15、在SQLite中,如何在一個表上添加或删除一列?

SQLite 有有限地 ALTER TABLE 支援。你可以使用它來在表的末尾增加一列,可更改表的名稱。 如果需要對表結構做更複雜的改變,則必須重建立表。 重建時可以先将已存在的資料放到一個臨時表中,删除原表, 建立新表,然後将資料從臨時表中複制回來。

如,假設有一個 t1 表,其中有 "a", "b", "c" 三列, 如果要删除列 c ,以下過程描述如何做:

BEGIN TRANSACTION;

CREATE TEMPORARY TABLE t1_backup(a,b);

INSERT INTO t1_backup SELECT a,b FROM t1;

DROP TABLE t1;

CREATE TABLE t1(a,b);

INSERT INTO t1 SELECT a,b FROM t1_backup;

DROP TABLE t1_backup;

COMMIT;

16、如何在Windows下編譯SQLite3

1)先從官網擷取sqlite-amalgamation-3_6_22.zip;

2)接着從官網擷取sqlitedll-3_6_22.zip

下載下傳編譯好的DLL,這裡有我們需要的sqlite3.def該檔案

3)打開VC建立一個“Win32 Dynamic-Link Library”工程,命名為:sqlite3;

4)在接下來的對話框中選擇"An empty DLL project",點 FINISH->OK;

5)将sqlite-amalgamation-3_6_22檔案夾下的sqlite3.h以及sqlite3.c兩個檔案複制到工程檔案夾下;

       将sqlitedll-3_6_22檔案夾下的sqlite3.def該檔案複制到工程檔案夾下;

6)在工程的Source Files中添加sqlite3.c檔案;

7)在工程的Include Files中添加sqlite3.h檔案;

8)在工程的Resource Files中添加sqlite3.def檔案;

9)針對如下問題:

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_column_database_name

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_column_database_name16

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_column_origin_name

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_column_origin_name16

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_column_table_name

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_column_table_name16

sqlite3.def : error LNK2001: unresolved external symbol sqlite3_table_column_metadata

Debug/sqlite3.lib : fatal error LNK1120: 7 unresolved externals

在菜單【Project】-【Settings…】-【C/C++】标簽下的Category【General】下

Preprocessor definitions下:

新增2個編譯選項,分别是:

THREADSAFE

SQLITE_ENABLE_COLUMN_METADATA

10)往工程中添加sqlite3.def檔案就是為生成sqlite3.lib檔案;

sqlite3.lib是與sqlite3.dll動态連結庫檔案一起提供給軟體開發者的;

11)解決Windows下的編譯警告

e:/sqlite/code/sqlite3/sqlite3.c(15385) : warning C4047: 'function' : 'void ** ' differs in levels of indirection from 'long *'

e:/sqlite/code/sqlite3/sqlite3.c(15385) : warning C4022: 'InterlockedCompareExchange' : pointer mismatch for actual parameter 1

e:/sqlite/code/sqlite3/sqlite3.c(15385) : warning C4022: 'InterlockedCompareExchange' : pointer mismatch for actual parameter 2

e:/sqlite/code/sqlite3/sqlite3.c(15403) : warning C4047: 'function' : 'void ** ' differs in levels of indirection from 'long *'

e:/sqlite/code/sqlite3/sqlite3.c(15403) : warning C4022: 'InterlockedCompareExchange' : pointer mismatch for actual parameter 1

e:/sqlite/code/sqlite3/sqlite3.c(15403) : warning C4022: 'InterlockedCompareExchange' : pointer mismatch for actual parameter 3

e:/sqlite/code/sqlite3/sqlite3.c(15403) : warning C4047: '==' : 'void *' differs in levels of indirection from 'const int '

e:/sqlite/code/sqlite3/sqlite3.c(65536) : warning C4049: compiler limit : terminating line number emission

warning C4761: integral size mismatch in argument; conversion supplied

warning C4761: integral size mismatch in argument; conversion supplied

warning C4761: integral size mismatch in argument; conversion supplied

VC2005 + SQLite 3.6.3 編譯、測試開發

http://blog.csdn.net/Dreamcode/archive/2009/08/21/4467277.aspx

17、SQLite一條SQL語句插入多條記錄,批量插入

用SQLite才發現這個文法并非标準SQL,故而SQLite并不支援。網絡上推薦的方法:

INSERT INTO TABLE(col1, col2) SELECT val11, val12 UNION ALL SELECT val21, val22 ;

這樣的寫法是屬于複合SQL語句,表示先把兩個SELECT的結果集進行無删減的聯合,再把聯合結果插入到TABLE中。

18、SQLite 插入大量資料慢(多次insert)的解決方法 

sqlite 插入資料很慢的原因:sqlite在沒有顯式使用事務的時候會為每條insert都使用事務操作,而sqlite資料庫是以檔案的形式存在磁盤中,就相當于每次通路時都要打開一次檔案,如果對資料進行大量的操作,時間都耗費在I/O操作上,是以很慢。

解決方法是顯式使用事務的形式送出:因為我們開始事務後,進行的大量操作的語句都儲存在記憶體中,當送出時才全部寫入資料庫,此時,資料庫檔案也就隻用打開一次。

https://www.cnblogs.com/likebeta/archive/2012/06/15/2551466.html

參考資料:

sqlite 中文社群:http://www.sqlite.com.cn/

sqlite 官方網站:http://www.sqlite.org/