mysql - varchar類型與數字的比較和轉換
convert(對象, 目標類型)是mysql中常用的類型轉換對象函數。eg:
select convert(‘1.123’, decimal(10.4))
,結果就是1.1230。對象可以用列名替代。前兩天發現,一個小伙伴之前設計表時把某個表數據類型設計成了varchar,實際用於存儲Decimal。我需要用其數據進行過濾篩選,這就造成了一些不便,所以記錄了本文。
如果文章內容有問題,歡迎評論或與我進行討論(請注明原因):
mail: wgh0807@qq.com
微信: hello-wgh0807
qq: 490536401
結論
使用convert或直接進行數字比較,在字符串與數字進行比較時,先對字符串進行了解析,遇到非數字類型(即字母等)會停止識別,然后將成功解析的部分(從左到右,異常為止)識別轉換為數字。如'1.56a8d7' -> 1.56
,'abcdefg...'->0
。
若確定數據實際上是數字類型,可以使用數字進行比較,如column>1.1
。
如果用到將數字存儲為字符串,需要轉換回數字或需要進行比較的操作,推薦使用convert方法。CONVERT(column, decimal(10,5))
,數據類型可以按照實際需要修改。
發現問題
我一直習慣於在idea中Database console 下直接編寫sql語句完成所有對數據庫的操作,這次也是,我使用了以下sql進行查詢:select * from test_table where volume > 0
。由於數據量較大,並沒有發現什么問題,過濾掉了0.0000,效率還不錯。
可是組長大大喜歡用navicat,畢竟可視化,查詢、修改也方便。於是我也下載了一個,直觀的修改條件,查看結果。但卻篩選到出了錯誤的結果(如下圖):
從圖中我們可以看到,在navicat的shaix中以volume>0,’0.00’竟然成功通過篩選!我當時就懷疑sql設計的問題
分析測試
這里需要注意,我直接構建sql篩選用到的是整型的0,在sql語句中為 volume> 0
,但是使用navicat時,由於表項類型是varchar,故其經過識別,在組裝成sql的時候變成volumn > '0'
,在比較過程中采用的是字符串的比較,故'0.0'>'0'
。
目測沒啥問題了,但是心虛的我又編寫了一個測試sql,用於計數:
select count(*) from (SELECT * FROM lh_dc_bond_price_net WHERE dq_volume > 0) a where dq_volume like '0.00%';
計數結果為空,我放心了。突然小伙伴-霖提問:如果出現字母會怎么樣呢?可以正確識別嗎?識別正確的部分?還是會報錯?
我做了個實驗:
select '1.23a>1.23','1.23a'>1.23 UNION select '1.23a<1.23','1.23a'<1.23 UNION select '1.23a=1.23','1.23a'=1.23;
SELECT '1a.23>1','1a.23'> 1 UNION SELECT '1a.23<1','1a.23'< 1 UNION SELECT '1a.23=1','1a.23'=1;
SELECT 'a>0','a'>0 UNION SELECT 'a<0','a'<0 UNION SELECT 'a=0','a'=0;
三次結果都是0,0,1
。由此可得,在字符串與數字進行比較時,先對字符串進行了解析,將成功解析的部分(從左到右,異常為止)識別轉換為數字。 此處和convert轉換結果相同。
小結:若需要進行比較,則可以直接讓字符串與數字進行比較。若需要獲得對象轉換后的值,則需要使用convert函數或cast進行轉換。
mysql 5.7 數據類型轉換方法總結
常用的轉換方法:BINARY、CAST、CONVERT。
-
BINARY expr
將對象轉換為二進制格式,常用語區分大小寫和檢測空格。 -
CAST(expr AS type)
:接收任意類型的表達式並生成指定類型的結果值,功能和語法類似於CONVERT。是標准SQL語法。 -
Convert(expr,type)
或Convert(expr using transcoding_name)
。可以采用任何類型表達式生成指定類型的結果值。Convert(expr,type)
等價於CAST(expr AS type)
函數。Convert(expr using transcoding_name)
是標准SQL語法。在不同編碼格式下轉換
convert未使用using 和 cast 時,type的類型可以包括以下值
-
BINARY[(N)]
生成具有BINARY數據類型的字符串 。有關如何影響比較的說明,請參見 第11.4.2節“BINARY和VARBINARY類型”。如果N給出了可選長度 ,則 會使強制轉換使用不超過 參數的字節。短於字節的值用字節填充到長度為 。 BINARY(N)NN0x00N
-
CHAR[(N)] [charset_info]
生成具有CHAR數據類型的字符串 。如果N給出了可選長度,則會使強制轉換使用不超過 參數的字符。對於短於字符的值,不會出現填充 。
如果沒有charset_info子句,則 CHAR生成具有默認字符集的字符串。要明確指定字符集,charset_info允許使用以下值:
-
CHARACTER SET charset_name:生成具有給定字符集的字符串。
-
ASCII:簡寫 CHARACTER SET latin1。
-
UNICODE:簡寫 CHARACTER SET ucs2。
在所有情況下,字符串都具有字符集的默認排序規則。
-
-
DATE
產生DATE值。
-
DATETIME
產生DATETIME值。
-
DECIMAL[(M[,D])]
產生DECIMAL值。如果給出了可選值M和 D值,則它們指定最大位數(精度)和小數點后面的位數(刻度)。
-
JSON (在MySQL 5.7.8中添加)
產生JSON值。有關在JSON其他類型之間轉換值的規則的詳細信息 ,請參閱 JSON值的比較和排序。
-
NCHAR[(N)]
類似CHAR,但會產生一個帶有國家字符集的字符串。請參見 第10.3.7節“國家字符集”。
與CHAR不同,NCHAR不允許指定尾隨字符集信息。
-
SIGNED [INTEGER]
生成有符號整數值。
-
TIME
產生TIME價值。
-
UNSIGNED [INTEGER]
生成無符號整數值。
更多信息請見 mysql 參考手冊
參考文檔:
MySQL中字符串與數字比較的坑 - Live In A Dream
mysql參考文檔 - 12.3.2 Comparison Functions and Operators
[mysql參考文檔 - 12.10 Cast Functions and Operators](