1. 程式人生 > >sqlite3常見錯誤原因

sqlite3常見錯誤原因



如何建立自動增長欄位?

簡短回答:宣告為 INTEGER PRIMARY KEY 的列將會自動增長

長一點的答案: 如果你宣告表的一列為 INTEGER PRIMARY KEY,那麼, 每當你在該列上插入一NULL值時, NULL自動被轉換為一個比該列中最大值大1的一個整數,如果表是空的, 將會是1。 (如果是最大可能的主鍵 9223372036854775807,那個,將鍵值將是隨機未使用的數。) 如,有下列表:

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錯誤程式碼。

多個應用程式或一個應用程式的多個例項可以同時訪問同一個資料庫檔案嗎?

多個程序可同時開啟同一個資料庫。多個程序可以同時進行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 函式調整這一行為。

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

如果你執行 sqlite3 命令列來訪問你的資料庫,可以鍵入 “.tables”來獲得所有表的列表。或者,你可以輸入 “.schema” 來看整個資料庫模式,包括所有的表的索引。 輸入這些命令,後面跟一個LIKE模式匹配可以限制顯示的表。

在一個 C/C++ 程式中(或者指令碼語言使用 Tcl/Ruby/Perl/Python 等) 你可以在一個特殊的名叫 SQLITE_MASTER 上執行一個SELECT查詢以獲得所有 表的索引。每一個 SQLite 資料庫都有一個叫 SQLITE_MASTER 的表, 它定義資料庫的模式。 SQLITE_MASTER 表看起來如下:

CREATE TABLE sqlite_master (
type TEXT,
name TEXT,
tbl_name TEXT,
rootpage INTEGER,
sql TEXT
);
對於表來說,type 欄位永遠是 'table',name 欄位永遠是表的名字。所以,要獲得資料庫中所有表的列表,使用下列SELECT語句:

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
對 於索引,type 等於 'index', name 則是索引的名字,tbl_name 是該索引所屬的表的名字。不管是表還是索引,sql 欄位是原先用 CREATE TABLE 或 CREATE INDEX 語句建立它們時的命令文字。對於自動建立的索引(用來實現 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

在SQLite中,VARCHAR欄位最長是多少?

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

SQLite支援二進位制大物件嗎?

SQLite 3.0 及以後版本允許你在任何列中儲存 BLOB 資料。 即使該列被宣告為其它型別也可以。

在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;

在資料庫中刪除了很多資料,但資料庫檔案沒有變小,是Bug嗎?

不是。當你從SQLite資料庫中刪除資料時, 未用的磁碟空間將會加入一個內部的“自由列表”中。當你下次插入資料時,這部分空間可以重用。磁碟空間不會丟失, 但也不會返還給作業系統。

如果刪除了大量資料,而又想縮小資料庫檔案佔用的空間,執行 VACUUM 命令。 VACUUM 將會從頭重新組織資料庫。這將會使用資料庫有一個空的“自由連結串列”, 資料庫檔案也會最小。但要注意的是,VACUUM 的執行會需要一些時間(在SQLite開發時,在Linux上,大約每M位元組需要半秒種),並且, 執行過程中需要原資料庫檔案至多兩倍的臨時磁碟空間。

對於 SQLite 3.1版本,一個 auto-vacumm 模式可以替代 VACUUM 命令。 可以使用 auto_vacuum pragma 開啟。

SQLITE_SCHEMA error是什麼錯誤?為什麼會出現該錯誤?

當一個準備好的(prepared)SQL語句不再有效或者無法執行時, 將返回一個 SQLITE_SCHEMA 錯誤。發生該錯誤時,SQL語句必須使用 sqlite3_prepare() API來重新編譯. 在 SQLite 3 中, 一個 SQLITE_SCHEMA 錯誤只會發生在用 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API 執行 SQL 時。而不會發生在使用 sqlite3_exec()時。 在版本2中不是這樣。

準備好的語句失效的最通常原因是:在語句準備好後, 資料庫的模式又被修改了。另外的原因會發生在:

資料庫離線:DETACHed.
資料庫被 VACUUMed
一個使用者儲存過程定義被刪除或改變。
一個 collation 序列定義被刪除或改變。
認證函式被改變。
在 所有情況下,解決方法是重新編譯並執行該SQL語句。 因為一個已準備好的語句可以由於其它程序改變資料庫模式而失效, 所有使用 sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API 的程式碼都應準備處理 SQLITE_SCHEMA 錯誤。下面給出一個例子:


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

    do {

sqlite3_prepare(pDb, zSql, -1, &pStmt, 0);

      while( SQLITE_ROW==sqlite3_step(pStmt) ){

}

     
rc = sqlite3_finalize(pStmt);
} while( rc==SQLITE_SCHEMA );

如何在字串中使用單引號(')?

SQL 標準規定,在字串中,單引號需要使用逃逸字元,即在一行中使用兩個單引號。在這方面 SQL 用起來類似 Pascal 語言。 SQLite 尊循標準。如:

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


Sqlite中如何返回本地化當前時間?
在做ClinicOS的時候遇到一個問題,在儲存病歷登記時間時,我使用了 “CURRENT_TIMESTAMP”,但這有個問題,它返回的是UTC Time,這對我們中國人沒啥用,一直希望能想辦法將它轉為localtime。今天剛好有空,所以去查了查Sqlite的Mail List,果然也有人遇到了這個問題,我從一篇名為《translate time comparison statement》(http://www.mail-archive.com/[email protected] /msg12350.html)中看到這樣的回覆:

Mark Wyszomierski wrote:
You may want
 
 
 
WHERE julianday(date('now')) - julianday(date(arrival_date)) > 7
Mark,

You should still use the 'localtime' modifier on the 'now' value if your timestamps are local time since 'now' always returns UTC times.

WHERE julianday(date('now', 'localtime')) - julianday(date(arrival_date)) > 7
 
 
 
嘿嘿,看來如果想得到一個符合本機區域設定的當前時間,必須用date函式來轉換,
 
但date只函式只返回當前日期,而我需要的是返回當前日期及時間,所以這裡把它換成datetime函式,即:
 
datetime(CURRENT_TIMESTAMP,'localtime')
 
 
 
以下是sqlite下測試的輸出資訊:
 
sqlite> select CURRENT_TIMESTAMP;
 
2006-06-18 09:23:36
 
sqlite> select datetime(CURRENT_TIMESTAMP,'localtime');
 
2006-06-18 17:23:44
 
sqlite>

SQLITE分頁

剛開始的時候沒注意語法
後來才發現,原來用SQLite分頁是世界上最簡單的。
如果我要去11-20的Account表的資料
Select * From Account Limit 9 Offset 10;
以上語句表示從Account表獲取資料,跳過10行,取9行

嗯,我覺得這個特性足夠讓很多的web中型網站使用這個了。

也可以這樣寫 select * from account limit10,9和上面的的效果一樣。
這種寫法MySQL也支援。

SQLite不同於其他大部分的SQL資料庫引擎,因為它的首要設計目標就是簡單化:

易於管理
易於使用
易於嵌入其他大型程式
易於維護和配置
許多人喜歡SQLite因為它的小巧和快速. 但是這些特性只是它的部分優點, 使用者還會發現SQLite是非常穩定的. 出色的穩定性源於它的簡單, 越簡單就越不容易出錯. 除了上述的簡單、小巧和穩定性外, 最重要的在於SQLite力爭做到簡單化.

簡單化在一個數據庫引擎中可以說是一個優點, 但也可能是個缺點, 主要決定於你想要做什麼. 為了達到簡單化, SQLite省略了一些人們認為比較有用的特性, 例如高併發性、嚴格的存取控制、 豐富的內建功能、 儲存過程、複雜的SQL語言特性、 XML以及Java的擴充套件, 超大的萬億級別的資料測量等等. 如果你需要使用上述的這些特性並且不介意它們的複雜性, 那麼SQLite也許就不適合你了. SQLite沒有打算作為一個企業級的資料庫引擎, 也並不打算和Oracle或者PostgreSQL競爭.

僅憑經驗來說SQLite適用於以下場合: 當你更看中簡單的管理、使用和維護資料庫, 而不是那些企業級資料庫提供的不計其數的複雜功能的時候,使用SQLite是一個比較明智的選擇. 事實也證明, 人們在許多情況下已經清楚的認識到簡單就是最好的選擇.

SQLite最佳試用場合
網站

作為資料庫引擎SQLite適用於中小規模流量的網站(也 就是說, 99.9%的網站). SQLite可以處理多少網站流量在於網站的資料庫有多大的壓力. 通常來說, 如果一個網站的點選率少於100000次/天的話, SQLite是可以正常執行的. 100000次/天是一個保守的估計, 不是一個準確的上限. 事實證明, 即使是10倍的上述流量的情況下SQLite依然可以正常執行.

嵌入式裝置和應用軟體

因為SQLite資料庫幾乎不需要管理, 因此對於那些無人值守執行或無人工技術支援的裝置或服務, SQLite是一個很好的選擇. SQLite能很好的適用於手機, PDA, 機頂盒, 以及其他儀器. 作為一個嵌入式資料庫它也能夠很好的應用於客戶端程式.

應用程式檔案格式

SQLite作為桌面應用程式的本地磁碟檔案格式取得了巨 大成功.例如金融分析工具、CAD 包、檔案管理程式等等. 一般的資料庫開啟操作需要呼叫sqlite3_open()函式,並且標記一個顯式本地事務的起始點(BEGIN TRANSACTION)來保證以獨佔的方式得到檔案的內容. 檔案儲存將執行一個提交(COMMIT)同時標記另一個顯式本地事務起始點. 這種事務處理的作用就是保證對於應用程式資料檔案的更新是原子的、持久的、獨立的和一致的.

資料庫裡可以加入一些臨時的觸發器,用來把所有的改變記錄在一張臨時的取消/重做日誌表中. 當用戶按下取消/重做按鈕的時候這些改變將可以被回滾. 應用這項技術實現一個無限級的取消/重做功能只需要編寫很少的程式碼.

替代某些特別的檔案格式

許多程式使用fopen(), fread(), 或 fwrite()函式建立和管理一些自定義的檔案用來儲存資料. 使用SQLite替代這些自定義的檔案格式將是一種很好的選擇.

內部的或臨時的資料庫

對於那些有大量的資料需要用不同的方式篩選分類的程式, 相對於編寫同樣功能的程式碼, 如果你把資料讀入一個記憶體中的SQLite資料庫, 然後使用連線查詢和ORDER BY子句按一定的順序和排列提取需要的資料, 通常會更簡單和快速. 按照上述的方法使用內嵌的SQLite資料庫將會使程式更富有靈活性, 因為新增新的列或索引不用重寫任何查詢語句.

命令列資料集分析工具

有經驗的SQL使用者可以使用SQLite命令列程式去分析各種混雜的資料集. 原是資料可以從CSV(逗號分隔值檔案)檔案中匯入, 然後被切分產生無數的綜合資料報告. 可能得用法包括網站日誌分析, 運動統計分析, 編輯規劃標準, 分析試驗結果.

當然你也可以用企業級的客戶端/伺服器資料庫來做同樣的事情. 在這種情況下使用SQLite的好處是: SQLite的部署更為簡單並且結果資料庫是一個單獨的檔案, 你可以把它儲存在軟盤或者優盤或者直接通過email發給同事.

在Demo或測試版的時候作為企業級資料庫的替代品

如果你正在編寫一個使用企業級資料庫引擎的客戶端程式, 使用一個允許你連線不同SQL資料庫引擎的通用型資料庫後臺將是很有意義的. 其更大的意義在於將SQLite資料庫引擎靜態的連線到客戶端程式當中,從而內嵌SQLite作為混合的資料庫支援. 這樣客戶端程式就可以使用SQLite資料庫檔案做獨立的測試或者驗證.

本文來自: (www.91linux.com) 詳細出處參考: