SQLite 完整中文FAQ

來源:互聯網
上載者:User
  --------------------------------------------------------------------------------

(1) 如何建立自增欄位?

簡單的回答:一個聲明為 INTEGER PRIMARY KEY 的欄位將自動增加。

這裡是詳細的答案: 從 SQLite 的 2.3.4 版本開始,如果你將一個表中的一個欄位聲明為 INTEGER PRIMARY KEY,那麼無論你何時向該表的該欄位插入一個 NULL 值,這個 NULL 值將自動被更換為比表中該欄位所有行的最大值大 1 的整數;如果表為空白,那麼將被更換為 1。比如,假設你有這樣的一張資料表:

CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b INTEGER
);
在這張資料表裡,聲明

INSERT INTO t1 VALUES(NULL,123);
在邏輯意義上等價於:

INSERT INTO t1 VALUES((SELECT max(a) FROM t1)+1,123);
一個新的API函數 sqlite3_last_insert_rowid() 返回最近的插入操作的整形鍵

注意這個整型鍵始終比之前插入表中的最後一個鍵大1。新鍵相對於表中的已有鍵來說是唯一的, 但它可能與之前從表中刪除的索引值重疊。要始終得到在整個表中唯一的鍵,在INTEGER PRIMARY KEY的聲明之前加關鍵詞AUTOINCREMENT.這樣被選的鍵將總是比表中已存在的最大鍵大1。若可能的 最大鍵已存在於表中,INSERT操作將失敗並返回一個SQLITE_FULL錯誤碼.

--------------------------------------------------------------------------------

(2) SQLite 支援哪些資料類型?

參見 http://www.sqlite.org/datatype3.html.

--------------------------------------------------------------------------------

(3) 為什麼能向 SQLite 資料庫的整型欄位中插入字串?

這是一個功能,不是一個 bug。你可以在任何欄位中放任何資訊,而不用管欄位聲明為什麼類型。 你可以往整型欄位中插入任意長度的字串,或者往布爾欄位中插入浮點數,或者往字元欄位中 插入日期。在 CREATE TABLE 命令中你指定給這個欄位的資料類型不會限制插入這個欄位的資料。 所有的欄位可以插入任意長度的字串。但對於 INTEGER PRIMARY KEY 欄位例外。這種欄位只能 存放一個64位的整數,否則會出錯。

但SQLite會預設你希望使用聲明的欄位類型。所以,比如你希望在一個聲明為INTEGER的欄位 中插入一個字串,SQLite會試圖將其轉換為一個整數。如果轉換成功,那麼整數將被插入,否 則插入字串,這種特性有時被稱作type or column affinity.

--------------------------------------------------------------------------------

(4) 為什麼 SQLite 認為運算式 '0'=='00' 為真?

在 2.7.0 之後,運算式不成立。參見文檔 datatypes in SQLite version 3

--------------------------------------------------------------------------------

(5) 為什麼 SQLite 不允許在同一張表裡使用 '0' 和 '0.0' 作為兩個不同的行的主鍵?

你的主鍵一定是數實值型別的,把類型改為 TEXT 就可以了。

每一行必須有一個唯一的主鍵。作為一個數字類型的欄位,SQLite 認為 '0' 和 '0.0'的值是相同的, 因為他們在數字上的比較是相等的(看前面的問題)因此值不是唯一的。

--------------------------------------------------------------------------------

(6) 為什麼不能在 Linux box 中讀取在 SparcStation 中建立的 SQLite 資料庫?

你需要升級你的 SQLite 庫到 2.6.3 或更新版本。

x86 處理器是 little-endian 型的而 Sparc 是 big-endian 型的。新版本的 SQLite 解決了這個問題。

註:   big endian和little endian是CPU處理多位元組數的不同方式。例如“漢”字的Unicode編碼是6C49。那麼寫到檔案裡時,究竟是將6C寫在前面,還是將49寫在前 面?如果將6C寫在前面,就是big endian。還是將49寫在前面,就是little endian。

--------------------------------------------------------------------------------

(7) 多個應用程式或者同一個應用程式的多個常式能同時存取同一個資料庫檔案嗎?

多進程可以同時開啟同一個資料庫,也可以同時 SELECT 。但只有一個進程可以立即改資料庫。

SQLite使用讀/寫鎖定來控制資料庫訪問。(Win95/98/ME 作業系統缺乏讀/寫鎖定支援,在低於 2.7.0 的版本中,這意味著在 windows 下在同一時間內只能有一個進程讀資料庫。在版本 2.7.0 中 這個問題通過在 windows 介面代碼中執行一個使用者間隔幾率讀寫鎖定策略解決了。) 但如果資料庫檔案在一個 NFS 檔案系統中,控制並發讀書的鎖定機制可以會出錯。因為 NFS 的fcntl() 檔案鎖定有時會出問題。如果有多進程可能並發讀資料庫則因當避免把資料庫檔案放在 NFS 檔案系統中。 根據微軟的文檔,如果不運行 Share.exe 背景程式則 FAT 檔案系統中的鎖定可能不工作。對 Windows 非常有經驗的人告訴我網路檔案的鎖定有許多問題並且不可靠。如果是這樣,在2個或以上 Windows 系統中共用一個 SQLite 資料庫檔案會導致不可預知的問題。

我們知道沒有其他的嵌入式 SQL資料庫引擎比SQLite支援更多的並發性。 SQLite允許多進程 同時開啟和讀取資料庫。任何一個進程需要寫入時,整個資料庫將在這一過程中被鎖定。但這一般僅耗時 幾毫秒。其他進程只需等待然後繼續其他事務。其他嵌入式SQL資料庫引擎往往只允許單進程訪問資料庫。

但是,client/server型的資料庫引擎 (如 PostgreSQL, MySQL, 以及 Oracle) 通常支援更高的並發度, 並支援多進程同時寫入同一個資料庫。由於總有一個控制良好的伺服器協調資料庫的訪問,這才保證了以上 特性的實現。如果你的應用需要很高的並發度,你應該考慮使用client/server資料庫。事實上,經驗告訴 我們大多數應用所需要的並發度比他們的設計者們想象的要少得多。

當 SQLite 嘗試操作一個被另一個進程鎖定的檔案時,預設的行為是返回 SQLITE_BUSY。你可以用 C代碼更改這一行為。 使用 sqlite3_busy_handler() 或sqlite3_busy_timeout() API函數。

如果兩個或更多進程同時開啟同一個資料庫,其中一個進程建立了新的表或索引,則其它進程可能不能立即看見新的表。其它進程可能需要關閉並重新連結資料庫。

--------------------------------------------------------------------------------

(8) SQLite是安全執行緒的嗎?

有時候是的。為了安全執行緒,SQLite 必須在編譯時間把 THREADSAFE 預先處理宏設為1。在預設的發行的已編譯版本中 Windows 版的是安全執行緒的,而 Linux 版的不是。如果要求安全執行緒,Linux 版的要重新編譯。

“安全執行緒”是指二個或三個線程可以同時調用獨立的不同的sqlite3_open() 返回的"sqlite3"結構。而不是在多線程中同時使用同一個 sqlite3 結構指標。

一個sqlite3結構只能在調用 sqlite3_open建立它的那個進程中使用。你不能在一個線程中開啟一個資料庫然後把指標傳遞給另一個線程使用。這是因為大多數多線程系統的限制 (或 Bugs?)例如RedHat9上。在這些有問題的系統上,一個 線程建立的fcntl()鎖不能由另一個線程刪除或修改。由於SQLite依賴fcntl()鎖來進行並發控制,當線上程間傳遞資料庫連接時會出現嚴重的 問題。

也許在Linux下有辦法解決fcntl()鎖的問題,但那十分複雜並且對於正確性的測試將是極度困難的。因此,SQLite目前不允許線上程間共用控制代碼。

在UNIX下,你不能通過一個 fork() 系統調用把一個開啟的 SQLite 資料庫放入子過程中,否則會出錯。

--------------------------------------------------------------------------------

(9) 如何列出一個 SQLite 資料庫中的所有的表/索引?

在sqlite3 命令列程式中你可以用命令 ".tables" 來顯示所有的表或者用 ".schema"來顯示所有的表結構和索引。但命令後不要跟 LIKE 語句,否則會限制表的顯示。

在 C/C++ 程式中 (或使用 Tcl/Ruby/Perl/Python綁定的指令碼中)你可以通過訪問名為"SQLITE_MASTER的表來實現。每個 SQLite 資料庫有一個 SQLITE_MASTER 表,表內有資料庫的結構。SQLITE_MASTER表是這樣的:

CREATE TABLE sqlite_master (
type TEXT,
name TEXT,
tbl_name TEXT,
rootpage INTEGER,
sql TEXT
);
對於表來說,type欄位的值為'table',name 欄位是表的名稱。使用以下語句可以等到所有表的列表:

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
對於索引來說, type = 'index', name 是索引的名稱, tbl_name 是索引所屬的表的名稱。對於表和索引,sql 欄位是建立表或索引的原始語句文本。對於自動建立的索引(一般是使用 PRIMARY KEY 或 UNIQUE 建立的),sql欄位為 NULL.

SQLITE_MASTER表是唯讀。你不能對該表使用 UPDATE, INSERT, 或 DELETE。該表自動由 CREATE TABLE, CREATE INDEX, DROP TABLE 和 DROP INDEX 命令更新。

暫存資料表及其索引不在 SQLITE_MASTER 表中而在 SQLITE_TEMP_MASTER 中出現。SQLITE_TEMP_MASTER 與 SQLITE_MASTER 表一樣工作,但只對於建立暫存資料表的程式可見。要得到所在表包括暫存資料表可以使用如下命令:

SELECT name FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
WHERE type='table'
ORDER BY name

--------------------------------------------------------------------------------

(10) SQLite資料庫是否有已知的大小限制?

資料庫大小被限制在 2TB(241 bytes). 這是理論限制。事實上,你應該把 SQLite資料庫的大小限制在100GB以下,以免出現運行效能上的問題。如果你需要儲存100GB或更多資料在一個資料庫中, 考慮使用為此而設計的企業版資料庫吧。

一個資料庫的理論行數限制是 264-1,顯然你會在達到行數限制之前先超過檔案大小的限制。目前一行可以存放 230 bytes 資料。而基本的檔案格式可以支援行大小到約 262 bytes.

可能還會有對於表、索引的數目或表和索引中的欄位數的限制,但沒人知道是多少。事實上,每當新資料庫開啟時,SQLite需要讀取和 分析所有表和索引聲明的初始SQL,所以,為了調用 sqlite3_open() 時獲得最佳效能,最好減少聲明的表的數目。同樣的,即使 對於表中欄位數沒有限制,多於100個也顯得太多了。 只有表開頭的31個欄位會得到最佳化。你可以在一個索引中放入任意多的欄位但超過30欄位的索引將不用於最佳化查詢。

表,索引,視圖,觸發器和欄位名稱可以任意長,但SQL 函數名 (由 sqlite3_create_function() API建立的)不得超過255個字元。

--------------------------------------------------------------------------------

(11) 在 SQLite 中 VARCHAR 的最大長度是多少?

SQLite不強制VARCHAR的長度。你可以聲明一個VARCHAR(10),SQLite一樣可以讓你存放500個字元在裡面。 並且它們會始終完整無缺——決不會被截斷。

--------------------------------------------------------------------------------

(12) SQLite 是否支援 BLOB 類型?

SQLite 3.0 版支援在任何欄位存放 BLOB 資料,不管欄位聲明為什麼類型。

--------------------------------------------------------------------------------

(13) 如何從一個已存在的 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;

--------------------------------------------------------------------------------

(14) 我刪除了很多資料但是資料庫檔案並沒有減小,是不是 Bug?

不是的。當你從 SQLite 刪除資料之後,未使用的磁碟空間被添加到一個內在的“空閑列表”中用於儲存你下次插入的資料。磁碟空間並沒有丟失,但是也不向作業系統返回磁碟空間。

如果你刪除了大量的資料且想要減小資料庫檔案,執行 VACUUM命令。VACUUM 命令會清空“空閑列表”,把資料庫尺寸縮到最小。注意, VACUUM 會耗費一些時間(在 Linux 系統下大約0.5秒/兆)並且要使用兩倍於資料庫檔案大小的磁碟空間。

對於SQLite version 3.1, 替代VACUUM命令的一個方法是auto-vacuum模式,用 auto_vacuum pragma文法開啟該模式。

--------------------------------------------------------------------------------

(15) 是否能將 SQLite 用於商業用途而不用交著作權費用?

可以。SQLite 是公開的。代碼的任何部分都沒有聲明所有權。你可以用它來做你想要的任何事情。

--------------------------------------------------------------------------------

(16) 如何插入有單引號(')的字串?

使用雙單引號即可,例如:

INSERT INTO xyz VALUES('5 O''clock');

插入資料庫的是:5 0'clock。

--------------------------------------------------------------------------------

(17) SQLITE_SCHEMA 錯誤代表什嗎?

在 SQLite 版本3中,當一個預先處理 SQL 陳述式不合法不能執行時就會返回一個 SQLITE_SCHEMA 錯誤。當這個錯誤發生時,該語句應當用 sqlite3_prepare() API函數重新編譯。在 SQLite 版本3中,只有使用 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API函數執行 SQL 才會發生這個錯誤,而使用 sqlite3_exec(). 則不會。這與版本2不同。

大部分發生這個錯誤的原因是當 SQL 預先處理完時資料庫已經改變了(可能是被另一個進程改變的)。還可能有如下原因:

對一個資料庫進行DETACH操作
對一個資料庫進行VACUUM操作
一個使用者函數定義被刪除或改變了。
一個排序定義被刪除或改變了。
一個授權函數改變了。
解決的辦法是重新編譯並再次嘗試執行。所有涉及 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API 函數的都應當重新編譯。參見下例:

int rc;
sqlite3_stmt *pStmt;
char zSql[] = "SELECT .....";

do {
/* Compile the statement from SQL. Assume success. */
sqlite3_prepare(pDb, zSql, -1, &pStmt, 0);

while( SQLITE_ROW==sqlite3_step(pStmt) ){
/* Do something with the row of available data */
}

/* Finalize the statement. If an SQLITE_SCHEMA error has
** occured, then the above call to sqlite3_step() will have
** returned SQLITE_ERROR. sqlite3_finalize() will return
** SQLITE_SCHEMA. In this case the loop will execute again.
*/
rc = sqlite3_finalize(pStmt);
} while( rc==SQLITE_SCHEMA );

--------------------------------------------------------------------------------

(18) 為什麼ROUND(9.95,1) 返回 9.9 而不是 10.0? 難道9.95 不該向上進位嗎?

SQLite 內部使用二進位運算,9.95用 64-bit IEEE 浮點數 ( SQLite 內部使用的) 表示為9.949999999999999289457264239899814128875732421875。所以當你輸入 "9.95"時,SQLite 就理解為上述的數字,進而四捨五入得到9.9。這個問題在處理浮點位元總會產生。通常的規則是十進位的有限浮點數通常無法表示為二進位有限浮點數,只 能由最接近的位元來代替。這個近似數會非常接近原數,但總一些細微的不同,所以可能無法得到你預期的結果。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.