Skip to content

Latest commit

 

History

History
80 lines (60 loc) · 4.03 KB

mysql-type-cast.md

File metadata and controls

80 lines (60 loc) · 4.03 KB

MySQL表达式计算中的类型转换

当操作符与不同类型的操作数在一起使用时,通过类型转换而使得操作数之间兼容。一些类型转换是隐式的。例如,MySQL会自动的在需要时,将数字转换成字符串,反之亦然。

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

还可以使用CAST()函数显式的将数字转换成字符串。CONCAT()函数能够隐式转换,是因为它需要字符串类型的参数。

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

下列规则描述了比较操作的转换规则:

  • 如果一个或是两个参数均为NULL,则比较结果是NULL,除了NULL安全的算子<=>。对于NULL <=> NULL,结果是true。不需要转换。
  • 如果比较操作中的两个参数都是字符串,则作为字符串进行比较。
  • 如果比较操作中的两个参数都是整数,则将他们作为整数进行比较。
  • 十六进制值如果不与数字进行比较,则视为二进制字符串。
  • 如果其中一个参数是TIMESTAMP或DATETIME列并且另一个参数是常量,那么在执行比较之前,该常量会转换为时间戳。这样做是对ODBC更加友好。对于IN()的参数,并没有转化。为了安全起见,在进行比较时,总是使用完整的DAATETIME/DATE或是TIME字符串。例如,使用BETWEEN做日期或时间比较时,显式的使用CAST()函数来将值转换为期望的数据类型。表的单行子查询不被视为常量。例如,如果子查询返回一个整数,该值将与DATETIME类型的值比较,则比较时会认为是两个整数比较。该整数不会被转为时间值。要将操作数作为DATETIME值进行比较,可以使用CAST()显式地将子查询值转换为DATETIME。
  • 如果其中一个参数是DECIMAL值,比较的时候,类型依赖于另一个参数。如果另一个参数是十进制或整数值,则将参数转化为十进制进行比较;如果另一个参数是浮点值,则将参数转化为浮点值比较。
  • 在所有其他情况下,参数都被作为浮点值进行比较。

下面例子说明了字符串转化为数字的比较操作:

mysql> SELECT 1 > '6x';
        -> 0
mysql> SELECT 7 > '6x';
        -> 1
mysql> SELECT 0 > 'x6';
        -> 0
mysql> SELECT 0 = 'x6';
        -> 1

当字符串类型的列使用数字比较时,MySQL无法再该列上使用索引加速查找。如果str_col是被索引的字符串列,当使用如下语句查询时索引无法使用:

SELECT * FROM tbl_name WHERE str_col = 1;

无法使用索引的原因是,有许多字符串都可以转换为1,例如'1', ‘ 1’或是'1a'。

使用浮点数(或是转化为浮点值)的比较时近似的,因为这些数字不是精确地。这可能会导致出现不一致的结果。

mysql> SELECT '18015376320243458' = 18015376320243458;
        -> 1
mysql> SELECT '18015376320243459' = 18015376320243459;
        -> 0

之所以会出现如此结果,是因为这些值被转化为浮点数,而浮点数只有53位精度,并且可以进行四舍五入:


mysql> SELECT '18015376320243459'+0.0;
        -> 1.8015376320243e+16

此外,从字符串到浮点数以及从整数到浮点数的转换不一定以相同的方式进行。在涉及浮点数乘法的操作中,整数可以由CPU转化为浮点数,而字符串是逐个数字进行转换的。

转换的结果,在不同的系统上会有所不同,并且会受到诸如计算机架构、编译器版本或是优化级别等因素的影响。避免此类问题的方法是使用CAST(),以便防止发生隐式转换。

mysql> SELECT CAST('18015376320243459' AS UNSIGNED) = 18015376320243459;
        -> 1

参考: