扩展 MySQL 8.0  / 第 6 章 向 MySQL 添加函数  /  12.3 表达式求值中的类型转换

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

当运算符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。一些转换隐式发生。例如,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'

有关隐式数字到字符串转换的字符集的信息,以及适用于CREATE TABLE ... SELECT 语句的修改规则,请参阅本节后面的内容。

以下规则描述了比较操作如何进行转换:

  • 如果一个或两个参数是NULL,则比较结果是NULL,但NULL-safe <=> 相等比较运算符除外。对于NULL <=> NULL,结果为真。无需转换。

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

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

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

  • 如果其中一个参数是 TIMESTAMPDATETIME列,而另一个参数是常量,则在执行比较之前将常量转换为时间戳。这样做是为了更加 ODBC 友好。这不是为 的参数完成的 IN()。为安全起见,在进行比较时始终使用完整的日期时间、日期或时间字符串。例如,要在 BETWEEN与日期或时间值一起使用时获得最佳结果,请使用CAST()将值显式转换为所需的数据类型。

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

  • 如果其中一个参数是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较,如果另一个参数是浮点值,则将作为浮点值进行比较。

  • 在所有其他情况下,参数将作为浮点(双精度)数字进行比较。例如,字符串和数字操作数的比较是作为浮点数的比较进行的。

有关将值从一种时间类型转换为另一种时间类型的信息,请参阅第 11.2.8 节,“日期和时间类型之间的转换”

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

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'

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

为了说明,只有以下比较中的第一个比较相等的值,但两个比较都返回 true (1):

mysql> SELECT '9223372036854775807' = 9223372036854775807;
        -> 1
mysql> SELECT '9223372036854775807' = 9223372036854775806;
        -> 1

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

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

有关浮点比较的更多信息,请参阅 第 B.3.4.8 节,“浮点值的问题”

服务器包括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+infNaN。后面的值不受支持,因为 SQL 标准将它们定义为 FLOAT或 的无效值DOUBLE

对于D-> F->D 转换,无损的充分条件是 D使用 15 位或更少的精度,不是非正规值、-inf+infNaN。在某些情况下,即使D 精度超过 15 位,转换也是无损的,但情况并非总是如此。

将数字或时间值隐式转换为字符串会生成一个值,该值具有由character_set_connectioncollation_connection系统变量确定的字符集和排序规则。(这些变量通常用 设置 SET NAMES。有关连接字符集的信息,请参阅 第 10.4 节,“连接字符集和排序规则”。)

这意味着此类转换会生成字符(非二进制)字符串(a CHARVARCHARLONGTEXT值),但连接字符集设置为 的情况除外 binary。在这种情况下,转换结果是二进制字符串(a BINARYVARBINARYLONGBLOB值)。

对于整数表达式,前面关于表达式求值的评论对表达式 赋值应用略有不同;例如,在这样的声明中:

CREATE TABLE t SELECT integer_expr;

在这种情况下,由表达式生成的列中的表具有类型INTor , BIGINT具体取决于整数表达式的长度。如果表达式的最大长度不适合INT, BIGINT则使用。长度取自结果集元数据 的max_length值 (请参阅C API 基本数据结构)。这意味着您可以强制而不是 使用足够长的表达式: SELECTBIGINTINT

CREATE TABLE t SELECT 000000000000000000000;