原本是因?yàn)橐粋€(gè)小小的問題,所以想對(duì)數(shù)據(jù)庫里的東西做個(gè)統(tǒng)計(jì),看看有沒有什么奇奇怪怪的數(shù)據(jù),然后就是漏打了個(gè)單引號(hào),發(fā)現(xiàn)了一個(gè)奇怪的現(xiàn)象。執(zhí)行的SQL如下:
select vc_full_name from t_fund_company_info WHERE vc_full_name=0;

結(jié)果發(fā)現(xiàn),哎,這怎么能查出數(shù)據(jù)庫里所有的數(shù)據(jù)呢,而且這里邊一個(gè)符合條件的結(jié)果都沒有,是不是MySQL抽了。
所以去問了一下別人,原來是MySQL的隱式轉(zhuǎn)換。
什么叫隱式轉(zhuǎn)換?
就是說,當(dāng)我們對(duì)不同類型的值進(jìn)行比較的時(shí)候,為了使得這些數(shù)值「可比較」(也可以稱為類型的兼容性),MySQL會(huì)做一些隱式轉(zhuǎn)化(Implicit type conversion)。
所以,上面那個(gè)語句,MySql在比較varchar類型和0的時(shí)候,會(huì)把varchar類型轉(zhuǎn)換成數(shù)字0
當(dāng)然MySQL也提供了這個(gè)cast()函數(shù),可以使用它來轉(zhuǎn)換成相應(yīng)的類型,就比如下面這個(gè)SQL:
select vc_full_name, ?cast(vc_full_name as SIGNED INTEGER) from t_fund_company_info;
結(jié)果如下:

那么,隱式轉(zhuǎn)換有什么規(guī)則呢,規(guī)則如下:
1.如果一個(gè)或兩個(gè)參數(shù)都是空的,比較的結(jié)果為null。null與null比較,結(jié)果為null,無需進(jìn)行轉(zhuǎn)換。
2.如果兩個(gè)比較的兩個(gè)參數(shù)都是string,按string比較,不做類型轉(zhuǎn)換。
3.如果兩個(gè)比較的兩個(gè)參數(shù)都是integer,按integer比較,不做類型轉(zhuǎn)換。
4.十六進(jìn)制的值和非數(shù)字做比較時(shí),會(huì)被當(dāng)做二進(jìn)制串來比較。
5.有一個(gè)參數(shù)是?TIMESTAMP?或?DATETIME,并且另外一個(gè)參數(shù)是常量,常量會(huì)被轉(zhuǎn)換為?timestamp。
6.有一個(gè)參數(shù)是?decimal?類型,如果另外一個(gè)參數(shù)是?decimal?或者整數(shù),會(huì)將整數(shù)轉(zhuǎn)換為?decimal?后進(jìn)行比較,如果另外一個(gè)參數(shù)是浮點(diǎn)數(shù),則會(huì)把?decimal?轉(zhuǎn)換為浮點(diǎn)數(shù)進(jìn)行比較
7.所有其他情況下,兩個(gè)參數(shù)都會(huì)被轉(zhuǎn)換為浮點(diǎn)數(shù)再進(jìn)行比較。
然后網(wǎng)上大家給出了一個(gè)需要注意的問題,就是:
假如password類型為字符串,查詢條件為 int 0 則會(huì)匹配上。
然后我就去數(shù)據(jù)庫操作了一下,發(fā)現(xiàn)有驚喜。

也就是說,這里是可以做SQL注入的。。如果網(wǎng)站登錄模塊做的比較挫的話。
所以說,為了防止在進(jìn)行查詢、更新或者刪除操作的時(shí)候,多操作更多的數(shù)據(jù),千萬記得寫SQL的時(shí)候加引號(hào)!
PS:最后沖哥還給出了一個(gè)重要結(jié)論, MySQL 隱式類型轉(zhuǎn)換本身也是非常耗費(fèi)?MySQL 服務(wù)器性能的,所以非常不推薦這樣使用。
第二個(gè)事情,是聚集函數(shù)的問題。這個(gè)聚集函數(shù),平時(shí)查數(shù)據(jù)庫也會(huì)用很多。
本來只想查下庫里一個(gè)文本字段,最大長(zhǎng)度是多少。結(jié)果發(fā)現(xiàn),這個(gè)里面的內(nèi)容跟對(duì)應(yīng)的長(zhǎng)度不符合。按照往常的習(xí)慣,沒多想,都是這樣寫的:
SELECT vc_fund_id,vc_fund_name,vc_Investment_field_txt,max(CHARACTER_LENGTH(vc_Investment_field_txt)) FROM t_fund_info;

但是TXT字段明顯沒有1305個(gè)字符。
后來才意識(shí)到,沒有加group by。。
在《數(shù)據(jù)庫系統(tǒng)概念》這本書中用如下的表述:
當(dāng)SQL查詢使用分組時(shí),一個(gè)很重要的事情是需要保證出現(xiàn)在select語句中但是沒有被聚集的屬性只能是出現(xiàn)在group by子句中的那些屬性,換句話說,任何沒有出現(xiàn)在group by子句中的屬性如果出現(xiàn)在select子句中的話,那么該屬性只能出現(xiàn)在聚集函數(shù)的內(nèi)部,否則,這樣的查詢就是錯(cuò)誤的。
所以說,比如有這樣一個(gè)表info,有如下字段:
id ?name ?num price
那么你這樣查:
select * from info group by id;
select id,sum(price) from info where price >= 10;
select id,count(price) from info where price >= 10;
select id, count(*) as num_prods, price from ?info where price >= 10;
這些都是錯(cuò)的!
第一個(gè)語句當(dāng)中,這個(gè)查詢按照id分組,然而select子句中的代表info中的所有屬性,更進(jìn)一步的,除了id之外,該表的其他屬性都未出現(xiàn)在group by子句中。所以是錯(cuò)的。
余下兩個(gè)也是一樣的。
最關(guān)鍵是,即使你這樣寫,MySQL也不會(huì)報(bào)錯(cuò)。。。但是結(jié)果卻讓你很困惑。。
大概所有數(shù)據(jù)庫都存在這種問題吧,像oracle、SQLserver等。