亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > MySQL > 正文

MySQL的隱式類型轉換整理總結

2024-07-24 13:11:45
字體:
來源:轉載
供稿:網友

前言

前幾天在看到一篇文章:價值百萬的 MySQL 的隱式類型轉換感覺寫的很不錯,再加上自己之前也對MySQL的隱式轉化這邊并不是很清楚,所以就順勢整理了一下。希望對大家有所幫助。

當我們對不同類型的值進行比較的時候,為了使得這些數值「可比較」(也可以稱為類型的兼容性),MySQL會做一些隱式轉化(Implicit type conversion)。

比如下面的例子:

mysql> SELECT 1+'1'; -> 2mysql> SELECT CONCAT(2,' test'); -> '2 test'

很明顯,上面的SQL語句的執行過程中就出現了隱式轉化。并且從結果們可以判斷出,第一條SQL中,將字符串的“1”轉換為數字1,而在第二條的SQL中,將數字2轉換為字符串“2”。

MySQL也提供了CAST()函數。我們可以使用它明確的把數值轉換為字符串。當使用CONCA()函數的時候,也可能會出現隱式轉化,因為它希望的參數為字符串形式,但是如果我們傳遞的不是字符串呢:

mysql> SELECT 38.8, CAST(38.8 AS CHAR); -> 38.8, '38.8'mysql> SELECT 38.8, CONCAT(38.8); -> 38.8, '38.8'

隱式轉化規則

官方文檔中關于隱式轉化的規則是如下描述的:

If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.

  • If both arguments in a comparison operation are strings, they are compared as strings.
  • If both arguments are integers, they are compared as integers.
  • Hexadecimal values are treated as binary strings if not compared to a number.
  • If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments to IN()! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.
    A single-row subquery from a table or tables is not considered a constant. For example, if a subquery returns an integer to be compared to a DATETIME value, the comparison is done as two integers. The integer is not converted to a temporal value. To compare the operands as DATETIME values, use CAST() to explicitly convert the subquery value to DATETIME.
  • If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.
  • In all other cases, the arguments are compared as floating-point (real) numbers.

翻譯為中文就是:

  1. 兩個參數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況都不需要做類型轉換
  2. 兩個參數都是字符串,會按照字符串來比較,不做類型轉換
  3. 兩個參數都是整數,按照整數來比較,不做類型轉換
  4. 十六進制的值和非數字做比較時,會被當做二進制串
  5. 有一個參數是 TIMESTAMP 或 DATETIME,并且另外一個參數是常量,常量會被轉換為 timestamp
  6. 有一個參數是 decimal 類型,如果另外一個參數是 decimal 或者整數,會將整數轉換為 decimal 后進行比較,如果另外一個參數是浮點數,則會把 decimal 轉換為浮點數進行比較
  7. 所有其他情況下,兩個參數都會被轉換為浮點數再進行比較

注意點

安全問題:假如 password 類型為字符串,查詢條件為 int 0 則會匹配上。

mysql> select * from test;+----+-------+-----------+| id | name | password |+----+-------+-----------+| 1 | test1 | password1 || 2 | test2 | password2 |+----+-------+-----------+2 rows in set (0.00 sec)mysql> select * from test where name = 'test1' and password = 0;+----+-------+-----------+| id | name | password |+----+-------+-----------+| 1 | test1 | password1 |+----+-------+-----------+1 row in set, 1 warning (0.00 sec)mysql> show warnings;+---------+------+-----------------------------------------------+| Level | Code | Message   |+---------+------+-----------------------------------------------+| Warning | 1292 | Truncated incorrect DOUBLE value: 'password1' |+---------+------+-----------------------------------------------+1 row in set (0.00 sec)

相信上面的例子,一些機靈的同學可以發現其實上面的例子也可以做sql注入。

假設網站的登錄那塊做的比較挫,使用下面的方式:

SELECT * FROM users WHERE username = '$_POST["username"]' AND password = '$_POST["password"]'

如果username輸入的是a' OR 1='1,那么password隨便輸入,這樣就生成了下面的查詢:

SELECT * FROM users WHERE username = 'a' OR 1='1' AND password = 'anyvalue'

就有可能登錄系統。其實如果攻擊者看過了這篇文章,那么就可以利用隱式轉化來進行登錄了。如下:

mysql> select * from test;+----+-------+-----------+| id | name | password |+----+-------+-----------+| 1 | test1 | password1 || 2 | test2 | password2 || 3 | aaa | aaaa || 4 | 55aaa | 55aaaa |+----+-------+-----------+4 rows in set (0.00 sec)mysql> select * from test where name = 'a' + '55';+----+-------+----------+| id | name | password |+----+-------+----------+| 4 | 55aaa | 55aaaa |+----+-------+----------+1 row in set, 5 warnings (0.00 sec)

之所以出現上述的原因是因為:

mysql> select '55aaa' = 55;+--------------+| '55aaa' = 55 |+--------------+| 1 |+--------------+1 row in set, 1 warning (0.00 sec)mysql> select 'a' + '55';+------------+| 'a' + '55' |+------------+| 55 |+------------+1 row in set, 1 warning (0.00 sec)

下面通過一些例子來復習一下上面的轉換規則:

mysql> select 1+1;+-----+| 1+1 |+-----+| 2 |+-----+1 row in set (0.00 sec)mysql> select 'aa' + 1;+----------+| 'aa' + 1 |+----------+| 1 |+----------+1 row in set, 1 warning (0.00 sec)mysql> show warnings;+---------+------+----------------------------------------+| Level | Code | Message  |+---------+------+----------------------------------------+| Warning | 1292 | Truncated incorrect DOUBLE value: 'aa' |+---------+------+----------------------------------------+1 row in set (0.00 sec)

把字符串“aa”和1進行求和,得到1,因為“aa”和數字1的類型不同,MySQL官方文檔告訴我們:

     When an operator is used with operands of different types, type conversion occurs to make the operands compatible.

查看warnings可以看到隱式轉化把字符串轉為了double類型。但是因為字符串是非數字型的,所以就會被轉換為0,因此最終計算的是0+1=1

上面的例子是類型不同,所以出現了隱式轉化,那么如果我們使用相同類型的值進行運算呢?

mysql> select 'a' + 'b';+-----------+| 'a' + 'b' |+-----------+|  0 |+-----------+1 row in set, 2 warnings (0.00 sec)mysql> show warnings;+---------+------+---------------------------------------+| Level | Code | Message    |+---------+------+---------------------------------------+| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' || Warning | 1292 | Truncated incorrect DOUBLE value: 'b' |+---------+------+---------------------------------------+2 rows in set (0.00 sec)

是不是有點郁悶呢?

之所以出現這種情況,是因為+為算術操作符arithmetic operator 這樣就可以解釋為什么a和b都轉換為double了。因為轉換之后其實就是:0+0=0了。

再看一個例子:

mysql> select 'a'+'b'='c';+-------------+| 'a'+'b'='c' |+-------------+|  1 |+-------------+1 row in set, 3 warnings (0.00 sec)mysql> show warnings;+---------+------+---------------------------------------+| Level | Code | Message    |+---------+------+---------------------------------------+| Warning | 1292 | Truncated incorrect DOUBLE value: 'a' || Warning | 1292 | Truncated incorrect DOUBLE value: 'b' || Warning | 1292 | Truncated incorrect DOUBLE value: 'c' |+---------+------+---------------------------------------+3 rows in set (0.00 sec)

現在就看也很好的理解上面的例子了吧。a+b=c結果為1,1在MySQL中可以理解為TRUE,因為'a'+'b'的結果為0,c也會隱式轉化為0,因此比較其實是:0=0也就是true,也就是1.

第二個需要注意點就是防止多查詢或者刪除數據

mysql> select * from test;+----+-------+-----------+| id | name | password |+----+-------+-----------+| 1 | test1 | password1 || 2 | test2 | password2 || 3 | aaa | aaaa || 4 | 55aaa | 55aaaa || 5 | 1212 | aaa || 6 | 1212a | aaa |+----+-------+-----------+6 rows in set (0.00 sec)mysql> select * from test where name = 1212;+----+-------+----------+| id | name | password |+----+-------+----------+| 5 | 1212 | aaa || 6 | 1212a | aaa |+----+-------+----------+2 rows in set, 5 warnings (0.00 sec)mysql> select * from test where name = '1212';+----+------+----------+| id | name | password |+----+------+----------+| 5 | 1212 | aaa |+----+------+----------+1 row in set (0.00 sec)

?上面的例子本意是查詢id為5的那一條記錄,結果把id為6的那一條也查詢出來了。我想說明什么情況呢?有時候我們的數據庫表中的一些列是varchar類型,但是存儲的值為‘1123'這種的純數字的字符串值,一些同學寫sql的時候又不習慣加引號。這樣當進行select,update或者delete的時候就可能會多操作一些數據。所以應該加引號的地方別忘記了。

關于字符串轉數字的一些說明

mysql> select 'a' = 0;+---------+| 'a' = 0 |+---------+| 1 |+---------+1 row in set, 1 warning (0.00 sec)mysql> select '1a' = 1;+----------+| '1a' = 1 |+----------+| 1 |+----------+1 row in set, 1 warning (0.00 sec)mysql> select '1a1b' = 1;+------------+| '1a1b' = 1 |+------------+|  1 |+------------+1 row in set, 1 warning (0.00 sec)mysql> select '1a2b3' = 1;+-------------+| '1a2b3' = 1 |+-------------+|  1 |+-------------+1 row in set, 1 warning (0.00 sec)mysql> select 'a1b2c3' = 0;+--------------+| 'a1b2c3' = 0 |+--------------+|  1 |+--------------+1 row in set, 1 warning (0.00 sec)

從上面的例子可以看出,當把字符串轉為數字的時候,其實是從左邊開始處理的。

  1. 如果字符串的第一個字符就是非數字的字符,那么轉換為數字就是0
  2. 如果字符串以數字開頭
  3. 如果字符串中都是數字,那么轉換為數字就是整個字符串對應的數字
  4. 如果字符串中存在非數字,那么轉換為的數字就是開頭的那些數字對應的值

總結

以上就是這篇文章的全部內容了,如果你有其他更好的例子,或者被隱式轉化坑過的情況,歡迎分享。希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。


注:相關教程知識閱讀請移步到MYSQL教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲午夜激情免费视频| xvideos亚洲| 亚洲老司机av| 精品一区二区三区四区在线| 亚洲性无码av在线| 成人av.网址在线网站| 8x拔播拔播x8国产精品| 欧美日韩不卡合集视频| 国产精品扒开腿爽爽爽视频| 国产经典一区二区| 精品亚洲一区二区三区在线观看| 欧洲日本亚洲国产区| 国产精品99蜜臀久久不卡二区| 欧美综合在线观看| 亚洲精品99久久久久| 亚洲免费伊人电影在线观看av| 91精品久久久久久久久| 国产一区二中文字幕在线看| 精品在线小视频| 4438全国成人免费| 欧美激情久久久久| 91国产中文字幕| 日韩av一区在线观看| 日韩视频―中文字幕| 在线播放国产精品| 久久久久一本一区二区青青蜜月| 欧美激情综合色综合啪啪五月| 亚洲性生活视频在线观看| 亚洲精品乱码久久久久久按摩观| 久久久久久久久网站| 精品伊人久久97| 亚洲福利视频网站| 91国产在线精品| 国产精品中文字幕在线观看| 色噜噜亚洲精品中文字幕| 亚洲最大福利视频网| 日韩美女av在线| 亚洲丝袜av一区| 久久国产精品首页| 久久99视频免费| 97色在线观看| 日韩av资源在线播放| 欧美影院久久久| 91社影院在线观看| 欧美大片第1页| 精品成人av一区| 91麻豆国产语对白在线观看| 国产精品久久久久久搜索| 久久天天躁狠狠躁老女人| 国产欧亚日韩视频| 国产精品女主播视频| 欧美精品制服第一页| 亚洲国产91色在线| 国产精品免费久久久久久| 亚洲综合一区二区不卡| 色诱女教师一区二区三区| 福利视频第一区| 国产伦精品免费视频| 欧美激情在线观看| 久久久欧美一区二区| 精品国产欧美一区二区三区成人| 久久色在线播放| 国产午夜精品全部视频在线播放| 青青久久aⅴ北条麻妃| 国产精品久久色| 久久av中文字幕| 国产精品白丝jk喷水视频一区| 国产精品国产亚洲伊人久久| 日韩精品在线免费观看视频| 57pao成人国产永久免费| 88国产精品欧美一区二区三区| 中文字幕av日韩| 亚洲福利在线看| 色偷偷噜噜噜亚洲男人的天堂| 精品福利视频导航| 日韩欧美视频一区二区三区| 亚洲欧美在线看| 国产精品国产三级国产专播精品人| 日韩成人在线观看| 日韩精品在线私人| 欧美在线性视频| 欧美一级在线亚洲天堂| 亚洲人成欧美中文字幕| 欧美日韩亚洲系列| 色妞久久福利网| 欧美激情国产高清| 国产精品免费一区| 国产精品美女免费| 欧美猛交免费看| 国产精品日韩在线播放| 91在线视频精品| 亚洲一区制服诱惑| 亚洲人成在线电影| 国产欧美一区二区| 国产日韩欧美一二三区| 亚洲欧美在线免费| 91成人在线视频| 亚洲成人激情视频| 久久综合国产精品台湾中文娱乐网| 98视频在线噜噜噜国产| 欧美色videos| 亚洲一区中文字幕在线观看| 亚洲a中文字幕| 欧美黑人一级爽快片淫片高清| 国模gogo一区二区大胆私拍| 日本精品久久久| 欧美国产第一页| 亚洲图片欧美日产| 欧美精品在线免费| 国产精品视频999| 动漫精品一区二区| 亚洲欧洲激情在线| 91免费视频网站| 色综合天天狠天天透天天伊人| 国产成人精品视频在线| 亚洲精品美女视频| 萌白酱国产一区二区| 国产亚洲aⅴaaaaaa毛片| 国产丝袜一区视频在线观看| 91夜夜未满十八勿入爽爽影院| 国产精品久久久久高潮| 日韩av在线导航| 2024亚洲男人天堂| 欧美日产国产成人免费图片| 美女精品视频一区| 日韩欧美在线视频日韩欧美在线视频| 国产精品久久久久久久久借妻| 久久久免费精品视频| 亚洲黄页视频免费观看| 久久久久久国产三级电影| 久久精品成人欧美大片古装| 色偷偷888欧美精品久久久| 久久精品2019中文字幕| 亚洲欧美日韩国产中文专区| 欧美大片在线看| 国自在线精品视频| 亚洲欧洲日产国码av系列天堂| 岛国av一区二区| 一本色道久久综合狠狠躁篇的优点| 久久av在线播放| 国内精品久久久久久久| 成人国产精品久久久久久亚洲| 激情av一区二区| 日韩a**站在线观看| 精品女同一区二区三区在线播放| 久久久久国产精品www| 亚洲xxxxx电影| 国产精品视频最多的网站| 日韩在线观看免费| 亚洲性无码av在线| 成人国产精品一区二区| 亚洲嫩模很污视频| 大胆欧美人体视频| 日韩精品在线播放| 中文字幕国产亚洲2019| 欧美精品在线免费| 欧美高清无遮挡| 国产亚洲精品久久久优势| 国产91在线播放精品91| 欧美主播福利视频| 欧美在线视频观看免费网站| 久久人人爽人人爽爽久久| 国产精品久久久久久久久久东京| 国产免费久久av|