原本是因為一個小小的問題凝垛,所以想對數(shù)據(jù)庫里的東西做個統(tǒng)計芭析,看看有沒有什么奇奇怪怪的數(shù)據(jù)凛捏,然后就是漏打了個單引號,發(fā)現(xiàn)了一個奇怪的現(xiàn)象烦磁。執(zhí)行的SQL如下:
select vc_full_name from t_fund_company_info WHERE vc_full_name=0;
結果發(fā)現(xiàn)养匈,哎,這怎么能查出數(shù)據(jù)庫里所有的數(shù)據(jù)呢都伪,而且這里邊一個符合條件的結果都沒有呕乎,是不是MySQL抽了。
所以去問了一下別人陨晶,原來是MySQL的隱式轉換猬仁。
什么叫隱式轉換?
就是說先誉,當我們對不同類型的值進行比較的時候湿刽,為了使得這些數(shù)值「可比較」(也可以稱為類型的兼容性),MySQL會做一些隱式轉化(Implicit type conversion)褐耳。
所以叭爱,上面那個語句,MySql在比較varchar類型和0的時候漱病,會把varchar類型轉換成數(shù)字0
當然MySQL也提供了這個cast()函數(shù)买雾,可以使用它來轉換成相應的類型把曼,就比如下面這個SQL:
select vc_full_name, ?cast(vc_full_name as SIGNED INTEGER) from t_fund_company_info;
結果如下:
那么,隱式轉換有什么規(guī)則呢漓穿,規(guī)則如下:
1.如果一個或兩個參數(shù)都是空的嗤军,比較的結果為null。null與null比較晃危,結果為null叙赚,無需進行轉換。
2.如果兩個比較的兩個參數(shù)都是string僚饭,按string比較孔庭,不做類型轉換。
3.如果兩個比較的兩個參數(shù)都是integer凄硼,按integer比較奇徒,不做類型轉換。
4.十六進制的值和非數(shù)字做比較時偿乖,會被當做二進制串來比較击罪。
5.有一個參數(shù)是?TIMESTAMP?或?DATETIME,并且另外一個參數(shù)是常量贪薪,常量會被轉換為?timestamp媳禁。
6.有一個參數(shù)是?decimal?類型,如果另外一個參數(shù)是?decimal?或者整數(shù)画切,會將整數(shù)轉換為?decimal?后進行比較竣稽,如果另外一個參數(shù)是浮點數(shù),則會把?decimal?轉換為浮點數(shù)進行比較
7.所有其他情況下霍弹,兩個參數(shù)都會被轉換為浮點數(shù)再進行比較丧枪。
然后網(wǎng)上大家給出了一個需要注意的問題,就是:
假如password類型為字符串庞萍,查詢條件為 int 0 則會匹配上拧烦。
然后我就去數(shù)據(jù)庫操作了一下,發(fā)現(xiàn)有驚喜钝计。
也就是說恋博,這里是可以做SQL注入的。私恬。如果網(wǎng)站登錄模塊做的比較挫的話债沮。
所以說,為了防止在進行查詢本鸣、更新或者刪除操作的時候疫衩,多操作更多的數(shù)據(jù),千萬記得寫SQL的時候加引號荣德!
PS:最后沖哥還給出了一個重要結論闷煤, MySQL 隱式類型轉換本身也是非常耗費?MySQL 服務器性能的童芹,所以非常不推薦這樣使用。
第二個事情鲤拿,是聚集函數(shù)的問題假褪。這個聚集函數(shù),平時查數(shù)據(jù)庫也會用很多近顷。
本來只想查下庫里一個文本字段生音,最大長度是多少。結果發(fā)現(xiàn)窒升,這個里面的內(nèi)容跟對應的長度不符合缀遍。按照往常的習慣,沒多想饱须,都是這樣寫的:
SELECT vc_fund_id,vc_fund_name,vc_Investment_field_txt,max(CHARACTER_LENGTH(vc_Investment_field_txt)) FROM t_fund_info;
但是TXT字段明顯沒有1305個字符域醇。
后來才意識到,沒有加group by冤寿。歹苦。
在《數(shù)據(jù)庫系統(tǒng)概念》這本書中用如下的表述:
當SQL查詢使用分組時青伤,一個很重要的事情是需要保證出現(xiàn)在select語句中但是沒有被聚集的屬性只能是出現(xiàn)在group by子句中的那些屬性督怜,換句話說,任何沒有出現(xiàn)在group by子句中的屬性如果出現(xiàn)在select子句中的話狠角,那么該屬性只能出現(xiàn)在聚集函數(shù)的內(nèi)部号杠,否則,這樣的查詢就是錯誤的丰歌。
所以說姨蟋,比如有這樣一個表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;
這些都是錯的立帖!
第一個語句當中眼溶,這個查詢按照id分組,然而select子句中的代表info中的所有屬性晓勇,更進一步的堂飞,除了id之外,該表的其他屬性都未出現(xiàn)在group by子句中绑咱。所以是錯的绰筛。
余下兩個也是一樣的。
最關鍵是描融,即使你這樣寫铝噩,MySQL也不會報錯。窿克。骏庸。但是結果卻讓你很困惑毛甲。。
大概所有數(shù)據(jù)庫都存在這種問題吧敞恋,像oracle丽啡、SQLserver等。