ITPub博客

首页 > 数据库 > > 12.2 在表达式评估的类型转换

12.2 在表达式评估的类型转换

作者:飘絮絮絮丶 时间:2020-05-12 10:34:32 0 删除 编辑

参考官方文档:

dev.mysql.com/doc/refma


当运算符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。 一些转换隐式发生。 例如,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,结果为true。 不需要转换。
  • 如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
  • 如果两个参数都是整数,则将它们作为整数进行比较。
  • 如果不与数字进行比较,则将十六进制值视为二进制字符串
  • 如果其中一个参数是TIMESTAMP或DATETIME列,而另一个参数是常量,则在执行比较之前,该常量将转换为时间戳。 这样做对ODBC更友好。 在in()中的参数不会这样做。 为了安全起见,在比较时总是使用完整的日期时间,日期或时间字符串。 例如,要在使用带日期或时间值的BETWEEN时实现最佳结果,请使用CAST()将值显式转换为所需的数据类型。

一个或多个表中的单行子查询不被视为常量。 例如,如果子查询返回要与DATETIME值进行比较的整数,则比较将作为两个整数完成。 整数不会转换为时间值。 要将操作数作为DATETIME值进行比较,请使用CAST()将子查询值显式转换为DATETIME。

  • 如果其中一个参数是十进制值,则比较取决于另一个参数。 如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较,如果另一个参数为浮点值,则将参数作为浮点值进行比较。
  • 在所有其他情况下,将参数作为浮点数(实数)进行比较。

JSON值的比较发生在两个层次上。 第一级比较基于比较值的JSON类型。 如果类型不同,则比较结果仅由哪种类型具有较高的优先级来确定。 如果这两个值具有相同的JSON类型,则会使用特定于类型的规则进行第二级比较。 为了比较JSON和非JSON值,将非JSON值转换为JSON,并将值作为JSON值进行比较。


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

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

该服务器包括dtoa,一个转换库,为改进字符串或DECIMAL值与近似值(FLOAT / DOUBLE)数字之间的转换提供了基础:

  • 跨平台的转换结果保持一致,例如,消除了Unix与Windows之间的转换差异。
  • 如果以前的结果不能提供足够的精度,例如接近IEEE限值的值,则可准确表示值。
  • 将数字转换为最佳精度的字符串格式。 dtoa的精度始终与标准C库函数的精度相同或更好。

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


dtoa库提供具有以下属性的转换。 D代表具有DECIMAL或字符串表示的值,F代表原生二进制(IEEE)格式的浮点数。

  • F - > D转换以尽可能最高的精度完成,返回D作为最短的字符串,当读回到内部时返回F并舍入到IEEE指定的本地二进制格式的最接近值。
  • 进行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系统变量确定的字符集和排序规则。 (这些变量通常使用SET NAMES设置。)

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


对于整数表达式,前面有关表达式的评估对于表达式分配的应用有所不同; 例如,在诸如此类的语句中:


CREATE TABLE t SELECT integer_expr;

在这种情况下,根据整数表达式的长度,由表达式生成的列中的表具有INT或BIGINT类型。 如果表达式的最大长度不适合INT,则使用BIGINT。 该长度取自SELECT结果集元数据的max_length值(请参见第27.8.5节“C API数据结构”)。 这意味着您可以通过使用足够长的表达式来强制使用BIGINT而不是INT:

CREATE TABLE t SELECT 000000000000000000000;

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3139279/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-09-09

  • 博文量
    2646
  • 访问量
    42374