今天浪費(fèi)了幾個(gè)小時(shí)在解決SQLite 3這個(gè)破問題。
情況是這樣的,有一張SQLite表,里面定義了幾個(gè)浮點(diǎn)和整形數(shù)據(jù),里面有一些看起來一模一樣的數(shù)據(jù)行, 我用upate把某些字段相除,結(jié)果大跌眼鏡,除的結(jié)果不一樣,有幾行把小數(shù)點(diǎn)扔掉了,變成整形相除,有些行又對? 要不都對,要不都錯(cuò),同樣的一個(gè)update對同樣數(shù)據(jù)行操作竟然能出現(xiàn)不同結(jié)果?完全顛覆了俺對數(shù)據(jù)庫的理解,還好經(jīng)過在MSSQL上測試是對的,MyGod,上帝保佑微軟!
后經(jīng)過反復(fù)測試,找到的解決方案是: 建表時(shí),不能用NUMERIC(14,3),不能用DECIMAL(14,3),必須指定為REAL型。否則,有可能100.00插到數(shù)據(jù)庫成100整形了,即使你定義的字段為浮點(diǎn)型。似乎SQLite表每一行的每一個(gè)字段都可以有自已的類型,根據(jù)插入的數(shù)值自動(dòng)進(jìn)行判斷,太TMD神奇了,這是那個(gè)神人的大腦想出來的,俺的SQL思想差點(diǎn)整崩潰。
下次打死也不用超出SQLITE那5個(gè)基本類型的字段類型,SQLITE的神奇轉(zhuǎn)換功能可能會(huì)讓你死的莫名其妙啊。記之。
網(wǎng)上google到的一篇文章,參考一下:
SQLITE數(shù)據(jù)類型(轉(zhuǎn)貼)
SQLite與其他常見的DBMS的最大不同是它對數(shù)據(jù)類型的支持。其他常見的DBMS通常支持強(qiáng)類型的數(shù)據(jù),
也就是每一列的類型都必須預(yù)先指定,但是SQLite采用的是弱類型的字段。實(shí)際上,其內(nèi)部僅有下列五種存儲(chǔ)類型:
NULL: 表示一個(gè)NULL值
INTEGER: 用來存儲(chǔ)一個(gè)整數(shù),根據(jù)大小可以使用1,2,3,4,6,8位來存儲(chǔ).
REAL: IEEE 浮點(diǎn)數(shù)
TEXT: 按照字符串來存儲(chǔ)
BLOB: 按照二進(jìn)制值存儲(chǔ),不做任何改變.
要注意,這些類型是值本身的屬性,而不是列的屬性.
但是為了和其他DBMS(以及SQL標(biāo)準(zhǔn))兼容,在其create table語句中可以指定列的類型,為此,SQLite有個(gè)列相似性的概念(Column Affinity). 列相似性是列的屬性,SQLite有以下幾種列相似性:
TEXT: TEXT列使用NULL,TEXT或者BLOB存儲(chǔ)任何插入到此列的數(shù)據(jù),如果數(shù)據(jù)是數(shù)字,則轉(zhuǎn)換為TEXT.
NUMERIC: NUMERIC列可以使用任何存儲(chǔ)類型,它首先試圖將插入的數(shù)據(jù)轉(zhuǎn)換為REAL或INTEGER型的,如果成功則存儲(chǔ)為REAL和INTEGER型,否則不加改變的存入.
INTEGER:和NUMERIC類似,只是它將可以轉(zhuǎn)換為INTEGER值都轉(zhuǎn)換為INTEGER,如果是REAL型,且沒有小數(shù)部分,也轉(zhuǎn)為INTEGER
REAL: 和NUMERIC類型 只是它將可以轉(zhuǎn)換為REAL和INTEGER值都轉(zhuǎn)換為REAL.
NONE:不做任何改變的嘗試.
SQLite根據(jù)create table語句來決定每個(gè)列的列相似性.規(guī)則如下(大小寫均忽略):
1. 如果數(shù)據(jù)類型中包括INT,則是INTEGER
2. 如果數(shù)據(jù)類型中包括CHAR,CLOB,TEXT則是TEXT
3. 如果數(shù)據(jù)類型中包括BLOB,或者沒有指定數(shù)據(jù)類型,則是NONE
4. 如果數(shù)據(jù)類型中包括REAL,FLOA或者DOUB,則是REAL
5. 其余的情況都是NUMERIC
由上可知,對于sqlite來說 char,varchar,nchar,nvarchar等都是等價(jià)的,且后面最大長度也是沒有意義的。但是對于其他DBMS卻不是相同的。另外,列相似性僅僅是向Sqlite提出了一個(gè)存儲(chǔ)數(shù)據(jù)的建議,即使實(shí)際存儲(chǔ)的數(shù)據(jù)類型和列相似性不一致,SQLite還是可以成功插入的,下面給出一個(gè)例子來說明下以上論述,注意,這個(gè)例子需要在SQLite的命令行下運(yùn)行,如果在SQLite Expert工具下執(zhí)行,SQLite會(huì)進(jìn)行一些額外的處理。
如下圖,創(chuàng)建一個(gè)新表,兩列的類型分別是int 和varchar,但是還是可以插入其他類型的數(shù)據(jù),并且可以正確讀出。
要注意SQLite的這種特性可能會(huì)給SQLite的ADO驅(qū)動(dòng)造成一些麻煩,因?yàn)?NET都是強(qiáng)類型的語言,必須把數(shù)據(jù)庫中的字段轉(zhuǎn)換為合適的類型,所以在插入數(shù)據(jù)的時(shí)候,還是應(yīng)該嚴(yán)格的按照create table中的定義插入數(shù)據(jù)。
(2)自增列
在SQL Server中,只需要指定identity(1,1)就可以設(shè)定自增列,但是在SQLite中不支持這樣做。在SQLite中,任何一張表都有一個(gè)字段類型是Integer,且是自增的,這個(gè)列是作為B樹的索引的,它的名字是ROWID,如下圖所示:
test2表雖然只有一列,但是ROWID列還是存在的。在程序中對任何一張表都可以使用ROWID作為自增列。不過這樣可能導(dǎo)致和其他數(shù)據(jù)庫的不兼容,SQLite中如果一個(gè)列的聲明類型是Integer,并且是主鍵,那么這個(gè)列的名字就成為ROWID的別名。注意,聲明類型必須是 Integer,而不能是int或bigint之類。例如:
注意上面例子的最后3條語句,它顯示了SQLite默認(rèn)的自增列算法是在當(dāng)前表中最大的數(shù)再加1,這樣可能導(dǎo)致的結(jié)果是ID被重復(fù)使用——當(dāng)最后一條數(shù)據(jù)被刪除的時(shí)候。這與SQL Server的Identity列的行為是不一致的,例如:
SQL Server會(huì)記住每一次插入的序號,哪怕它已經(jīng)被刪除了。要實(shí)現(xiàn)SQL Server 這樣的效果,需要使用autoincrement關(guān)鍵字。如下例所示:
不過 autoincrement關(guān)鍵字不被SQL Server支持(我不知道SQL 92標(biāo)準(zhǔn)中是否有此關(guān)鍵字),同樣SQL Server的 indentity關(guān)鍵字在SQLite中也無法使用,因?yàn)镾QLite只要求聲明類型必須是integer才可以啟用自增列。所以,我想不出什么方法能使建庫的腳本能夠不加修改的被兩種數(shù)據(jù)庫使用。
(3) 日期函數(shù)
Sqlite的日期函數(shù)比較有特色,它的使用本質(zhì)上是調(diào)用C的庫函數(shù)strftime,基本使用方法如下:
(4) 不被支持的特性
用戶自定義函數(shù),存儲(chǔ)過程
|