提問
乙個粗心,括號不小心打錯了地方,猜猜會是什麼執行結果?
t_***表order_no為varchar型別。
select * from t_*** where order_no in ('u123','u234' and type in (10,11));
語法錯誤?
row 0?
答案
實際情況是,這句sql並沒有語法錯誤,而是將全部資料返回出來。
本以為這句sql會報語法錯誤,但萬萬沒想到竟然可以執行成功,而且會導致where子句的失效,讓我們一起盤根問底一下。
首先是詞法分析
mysql通過關鍵字將sql語句進行解析,並生成一棵對應的「解析樹」。mysql解析器將使用mysql語法規則驗證和解析查詢。
1. 本例中,in將被分解為【'u123'】、【'u234' and type in (10,11)】兩部分,也同時等效於order_no=('u123') or order_no=('u234' and type in (10,11)),前一段必定是false,出問題的部分其實就在後面這段。
2. 猜想下('u234' and type in (10,11))的結果是什麼?因為中間有and邏輯運算子,其結果將為布林型(底層為tinyint(1)),0/1這樣的值
那為什麼後面一段會被認為是true呢?這就要從varchar與int的比較說起,這也是乙個會隱藏大坑的地方《資料型別隱式轉換》
資料型別隱式轉換分析
文件我們只看原版:
首先我們列舉下已知的隱式轉換規則:
兩個引數至少有乙個是 null 時,比較的結果也是 null,例外是使用 <=> 對兩個 null 做比較時會返回 1,這兩種情況都不需要做型別轉換
兩個引數都是字串,會按照字串來比較,不做型別轉換
兩個引數都是整數,按照整數來比較,不做型別轉換
十六進製制的值和非數字做比較時,會被當做二進位制串
有乙個引數是 timestamp 或 datetime,並且另外乙個引數是常量,常量會被轉換為 timestamp
有乙個引數是 decimal 型別,如果另外乙個引數是 decimal 或者整數,會將整數轉換為 decimal 後進行比較,如果另外乙個引數是浮點數,則會把 decimal 轉換為浮點數進行比較
所有其他情況下,兩個引數都會被轉換為浮點數再進行比較
【order_no=('u234' and type in (10,11))】出問題的條件表示式,order_no是字串、後面的是tinyint(1),等價於order_no=0這個條件表示式,**了,命中了7號策略
我們又要細說,字元轉數字的過程
字串轉為數字
乙個字串是會與int 0匹配上的,這也是乙個經典的安全問題,那為什麼字串或者明確說首字母非數字的字串會與int 0匹配上呢?
再來猜測一下,這些表示式的結果會是什麼?
select '123'=123,'123a'=123,'a123'=123---------------------1 1 0---------------------
當字串轉為數字的時候,原則是從左邊開始處理:
如果字串的第乙個字元就是非數字的字元,那麼轉換為數字就是0
如果字串以數字開頭
如果字串中都是數字,那麼轉換為數字就是整個字串對應的數字
如果字串中存在非數字,那麼轉換為的數字就是開頭的那些數字對應的值
所以order_no變成了0,與右側的0匹配上了
這就是這個問題的分析過程
js 引起的隱式轉換
var undefined undefined null true 1 true true 2 true false 0 false true 0 true nan nan false false true true alert true alert false alert 0 true alert...
mysql 隱式轉換 mysql中的隱式轉換
在mysql查詢中,當查詢條件左右兩側型別不匹配的時候會發生隱式轉換,可能導致查詢無法使用索引。下面分析兩種隱式轉換的情況 看表結構 phone為 int型別,name為 varchar 兩種情況都可以用到索引,這次等號右側是 2 注意帶單引號喲,左側的索引欄位是int型別,因此也會發生隱式轉換,但...
mysql隱式轉換
定義 當操作符與不同型別的運算元一起使用時,會發生型別轉換以使運算元相容。則會發生轉換隱式 舉乙個常見例子 1 我們先建立乙個表,有關手機號查詢 create table user id int 11 not null primary keyauto increment phone varchar ...