公司項目代碼中,某枚舉字段數據庫表中類型是char(1),在代碼中,誤覺得是TINYINT,因此用數字篩選,後來發現結果不對。發現了一個現象,用數字0篩選會把全部的記錄給篩選出來。
通過排查發現是在MySQL查詢語句中,'abc'若是和'0'比較結果顯然是不等的,但若是'abc'和0比較呢?結果竟然是相等的。html
隨意測試了幾下,結果以下:mysql
mysql> select 'abc'=0; +---------+ | 'abc'=0 | +---------+ | 1 | +---------+ 1 row in set, 1 warning (0.00 sec)
mysql> select '0abc'=0; +----------+ | '0abc'=0 | +----------+ | 1 | +----------+ 1 row in set, 1 warning (0.00 sec)
mysql> select '01abc'=0; +-----------+ | '01abc'=0 | +-----------+ | 0 | +-----------+ 1 row in set, 1 warning (0.00 sec)
mysql> select '013abc'=13; +-------------+ | '013abc'=13 | +-------------+ | 1 | +-------------+ 1 row in set, 1 warning (0.00 sec)
以上幾個查詢經過查看MySQL給出的警告,均可以看到相似以下的信息sql
mysql> show warnings; +---------+------+--------------------------------------------+ | Level | Code | Message | +---------+------+--------------------------------------------+ | Warning | 1292 | Truncated incorrect DOUBLE value: '013abc' | +---------+------+--------------------------------------------+ 1 row in set (0.00 sec)
查閱MySQL 5.7官方文檔中關於比較的章節,其中說明Strings are automatically converted to numbers and numbers to strings as necessary.
。也就是說在比較的時候,String是可能會被轉爲數字的。數據庫
而對於數字開頭的字符串來講,轉爲數字的結果就是截取前面的數字部分測試
mysql> select cast('123abc' as signed); +-----------------------------+ | cast('123abc' as signed) | +-----------------------------+ | 123 | +-----------------------------+ 1 row in set, 1 warning (0.00 sec)
mysql> select cast('123.45abc' as decimal(5,2)); +-----------------------------------+ | cast('123.45abc' as decimal(5,2)) | +-----------------------------------+ | 123.45 | +-----------------------------------+ 1 row in set (0.00 sec)
mysql> select cast('abc' as signed); +-----------------------+ | cast('abc' as signed) | +-----------------------+ | 0 | +-----------------------+ 1 row in set, 1 warning (0.00 sec)
而對於開頭部分不能截取出數字的字符串來講,轉換的結果天然就是0了。code
關於字符串類型與整數直接進行比較的坑,說穿了就是MySQL中字符串轉爲數字的邏輯,沒遇到過確實可能不太清楚,遇到過一次之後經驗就是,看清楚數據庫表字段,儘可能避免字符串與數字的直接比較。htm
此外,書寫sql語句的時候務必注意不要犯類型的錯誤,也許查出來的結果是對的,可是因爲類型不匹配的緣由,將會致使表索引沒法用上。索引