玖叶教程网

前端编程开发入门

MySQL表达式求值中的类型转换

MySQL表达式求值中的类型转换

当运算符用于不同类型的操作数时,会发生类型转换以使操作数兼容。有些转换是隐式发生的。例如,MySQL会根据需要自动将字符串转换为数字,反之亦然。

mysql> SELECT 1+'1';

+-------+

| 1+'1' |

+-------+

| 2 |

+-------+

1 row in set (0.00 sec)


mysql> SELECT CONCAT(2,' test');

+-------------------+

| CONCAT(2,' test') |

+-------------------+

| 2 test |

+-------------------+

1 row in set (0.00 sec)


也可以使用CAST()函数将数字显式转换为字符串。CONCAT()函数隐式进行转换,因为它要求字符串参数。

mysql> SELECT 38.8, CAST(38.8 AS CHAR);

+------+--------------------+

| 38.8 | CAST(38.8 AS CHAR) |

+------+--------------------+

| 38.8 | 38.8 |

+------+--------------------+

1 row in set (0.00 sec)


mysql> SELECT 38.8, CONCAT(38.8);

+------+--------------+

| 38.8 | CONCAT(38.8) |

+------+--------------+

| 38.8 | 38.8 |

+------+--------------+

1 row in set (0.00 sec)



以下规则描述了比较操作的转换方式:

1.如果一个或两个参数都为NULL,比较的结果是NULL,除了NULL <=> 安全等于运算符。对于表达式 NULL <=> NULL,结果是真的。不需要转换。


2.如果比较操作中的两个参数都是字符串,则它们作为字符串进行比较。


3.如果两个参数都是整数,则它们作为整数进行比较。


4.如果不与数字进行比较,十六进制值将被视为二进制字符串。


5.如果其中一个参数是TIMESTAMP或者DATETIME列,而另一个参数是常量,则在执行比较之前,该常量会被转换为时间戳。这样做是为了更好地支持ODBC。对于IN()里面的参数,则不会这样做。为了安全起见,在进行比较时,请始终使用完整的日期时间、日期或时间字符串。例如,在使用BETWEEN对日期或时间值比较时,为了达到最大的效果,请使用CAST()显式转换为所需的数据类型。


来自一个或多个表的单行子查询不被视为常量。例如,如果子查询返回一个整数,需要与DATETIME类型值比较,则表达式最终是两个整数进行比较。整数不会转换为时间值。要想作为DATETIME类型值比较,需要使用CAST()将子查询的值显式转换为DATETIME。


6.如果其中一个参数是十进制值,进行比较时依赖于另一个参数。如果另一个参数是十进制值或整数值,则将这些参数作为十进制值进行比较;如果另一个参数是浮点值,则将这些参数作为浮点值进行比较。


7.在除了以上几点外的所有其他情况下,参数作为浮点数(双精度)进行比较。例如,字符串和数字的比较就像浮点数的比较一样。


有关时间类型的转换,参考官方文档:https://dev.mysql.com/doc/refman/8.0/en/date-and-time-type-conversion.html Section 11.2.8, Conversion Between Date and Time Types.


JSON值的比较发生在两个层次上。第一级比较基于被比较值的JSON类型。如果类型不同,则比较结果仅由优先级较高的类型决定。如果两个值具有相同的JSON类型,则使用特定类型的规则进行第二级比较。对于JSON和非JSON值的比较,非JSON值被转换为JSON值,并且这些值作为JSON值进行比较。有关详细信息,请参见JSON值的比较和排序(https://dev.mysql.com/doc/refman/8.0/en/json.html#json-comparison).



以下示例说明了比较操作中字符串到数字的转换:


mysql> SELECT 1 > '6x';

+----------+

| 1 > '6x' |

+----------+

| 0 |

+----------+

1 row in set, 1 warning (0.00 sec)


mysql> SELECT 7 > '6x';

+----------+

| 7 > '6x' |

+----------+

| 1 |

+----------+

1 row in set, 1 warning (0.00 sec)


mysql> SELECT 0 > 'x6';

+----------+

| 0 > 'x6' |

+----------+

| 0 |

+----------+

1 row in set, 1 warning (0.01 sec)


mysql> SELECT 0 = 'x6';

+----------+

| 0 = 'x6' |

+----------+

| 1 |

+----------+

1 row in set, 1 warning (0.00 sec)


对于字符串列与数字的比较,MySQL不能使用列上的索引来快速查找值。如果str_col是索引字符串列,则在以下语句中执行查找时不能使用索引:

SELECT * FROM tbl_name WHERE str_col=1;


这是因为有许多不同的字符串可以转换为值1,比如'1', ' 1',或者'1a'。


浮点数和比较大的INTEGER类型比较时是近似的,因为整数在比较之前被转换为双精度浮点型,这无法精确表示所有64位整数。例如,整数值2^53+1不可表示为浮点型,在浮点数比较前四舍五入为2^53或者2^53+2,具体取决于平台。


举例来说,只有下面的第一个比较是等值比较,但是两个比较都返回true (1):


mysql> SELECT '9223372036854775807' = 9223372036854775807;

+---------------------------------------------+

| '9223372036854775807' = 9223372036854775807 |

+---------------------------------------------+

| 1 |

+---------------------------------------------+

1 row in set (0.00 sec)


mysql> SELECT '9223372036854775807' = 9223372036854775806;

+---------------------------------------------+

| '9223372036854775807' = 9223372036854775806 |

+---------------------------------------------+

| 1 |

+---------------------------------------------+

1 row in set (0.00 sec)


当发生从字符串到浮点数和从整数到浮点数的转换时,它们不一定以相同的方式发生。CPU可能会将整数转换成浮点,而字符串在涉及浮点数乘法的操作中被逐位转换。此外,结果可能会受到计算机体系结构、编译器版本或优化级别等因素的影响。避免此类问题的一种方法是使用CAST()以便值不会隐式转换为浮点数:


mysql> SELECT CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806;

+---------------------------------------------------------------+

| CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806 |

+---------------------------------------------------------------+

| 0 |

+---------------------------------------------------------------+

1 row in set (0.00 sec)


有关浮点比较的更多信息,参考官方文档:https://dev.mysql.com/doc/refman/8.0/en/problems-with-float.html Section B.3.4.8, “Problems with Floating-Point Values”.


server包括dtoa转换库,为改进字符串或DECIMAL值和近似值(FLOAT/DOUBLE)数字转换提供基础:

1.跨平台的一致转换结果,例如,消除了Unix与Windows之间的转换差异。

2.在先前结果不能提供足够精度的情况下,精确表示值,例如接近IEEE上限的值。

3.尽可能精确地将数字转换为字符串格式。dtoa的精度总是与标准C库函数相同或更好。


因为该库产生的转换在某些情况下不同于非dtoa结果,依赖于先前结果的应用程序中可能存在不兼容性。例如,依赖于先前转换的特定精确结果的应用可能需要调整以适应更高的精度。


dtoa库提供了具有以下属性的转换。D用表示一个值DECIMAL或字符串表示形式,并且F表示本机二进制(IEEE)格式的浮点数。


F -> D 转换以尽可能高的精度完成,将F以二进制格式四舍五入后返回最短的字符串转换为D。


D -> F 转换是这样进行的,将F转换为与十进制数D最接近的二进制数。


这些特性意味着F -> D -> F转换是无损的,除非F是-inf, +inf,或者NaN。不支持后面这种值,因为SQL标准将它们定义为的无效值FLOAT或者DOUBLE.


为D -> F -> D转换,无损的充分条件是D使用15位或更少位数的精度,而不是非规范的值,-inf, +inf,或者NaN。在某些情况下,即使D具有超过15位的精度转换也是无损的,但情况并非总是如此。


数字或时间值到字符串的隐式产生的结果值由character_set_connection和collation_connection系统变量决定。有关连接字符集的信息,参考官方文档:https://dev.mysql.com/doc/refman/8.0/en/charset-connection.html


这意味着这种转换会产生一个字符(非二进制)字符串(a CHAR, VARCHAR,或者LONGTEXT值),除非连接字符集设置为binary。在这种情况下,转换结果是二进制字符串(a BINARY, VARBINARY,或者LONGBLOB值)。


对于整数表达式,前面关于表达式的说明应用,稍微不同与表达式赋值语句;例如,在这样的语句中:


CREATE TABLE t SELECT integer_expr;

在这种情况下,表达式生成的列中的表的类型为INT或者BIGINT这取决于整数表达式的长度。如果表达式的最大长度不是INT, 则使用BIGINT。长度取自选择结果集元数据的max_length值(请参考:https://dev.mysql.com/doc/c-api/8.0/en/c-api-data-structures.html).这意味着您可以强制一个BIGINT而不是INT通过使用足够长的表达式:


CREATE TABLE t SELECT 000000000000000000000;

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言