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

[](<>)[](<>)

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

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

也可以使用显式将数字转换为字符串[`投掷（）`](cast-functions.html#function_cast)功能。转换隐式发生[`连接（）`](string-functions.html#function_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'
```

有关隐式数字到字符串转换的字符集的信息，以及适用于`创建表...选择`陈述。

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

-   如果一个或两个参数是`空值`，比较的结果是`空值`, 除了`空值`-安全的[`<=>`](comparison-operators.html#operator_equal-to)相等比较运算符。为了`空<=>空`，结果为真。无需转换。

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

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

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

-   如果其中一个参数是[`时间戳`](datetime.html)要么[`约会时间`](datetime.html)column 并且另一个参数是一个常量，该常量在执行比较之前转换为时间戳。这样做是为了对 ODBC 更友好。这不是为[`在（）`](comparison-operators.html#operator_in).为了安全起见，在进行比较时，请始终使用完整的日期时间、日期或时间字符串。例如，为了在使用时达到最佳效果[`之间`](comparison-operators.html#operator_between)使用日期或时间值，使用[`投掷（）`](cast-functions.html#function_cast)将值显式转换为所需的数据类型。

    来自一个或多个表的单行子查询不被视为常量。例如，如果子查询返回要与[`约会时间`](datetime.html)值，比较是作为两个整数进行的。整数不会转换为时间值。将操作数比较为[`约会时间`](datetime.html)价值观，使用[`投掷（）`](cast-functions.html#function_cast)将子查询值显式转换为[`约会时间`](datetime.html).

    [](<>)[](<>)

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

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

    有关将值从一种时间类型转换为另一种的信息，请参阅[第 11.2.7 节，“日期和时间类型之间的转换”](date-and-time-type-conversion.html).

    JSON 值的比较发生在两个级别。第一级比较基于比较值的 JSON 类型。如果类型不同，则比较结果仅取决于哪种类型具有更高的优先级。如果两个值具有相同的 JSON 类型，则使用特定于类型的规则进行第二级比较。为了比较 JSON 和非 JSON 值，将非 JSON 值转换为 JSON，并将值作为 JSON 值进行比较。有关详细信息，请参阅[JSON值的比较和排序](json.html#json-comparison).

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


```
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'`.

浮点数与大值的比较`整数`类型是近似的，因为整数在比较之前被转换为双精度浮点数，它不能精确地表示所有 64 位整数。例如，整数值 2<sup>53</sup>+ 1 不能表示为浮点数，四舍五入为 2<sup>53</sup>或 2<sup>53</sup>+ 2 在浮点比较之前，取决于平台。

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

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

当发生从字符串到浮点以及从整数到浮点的转换时，它们的发生方式不一定相同。CPU 可以将整数转换为浮点数，而字符串在涉及浮点乘法的操作中逐位转换。此外，结果可能会受到计算机体系结构或编译器版本或优化级别等因素的影响。避免此类问题的一种方法是使用[`投掷（）`](cast-functions.html#function_cast)这样一个值就不会隐式转换为浮点数：

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

有关浮点比较的更多信息，请参阅[第 B.3.4.8 节，“浮点值问题”](problems-with-float.html).

服务器包括`dtoa`，一个转换库，为改进字符串或字符串之间的转换提供基础[`十进制`](fixed-point-types.html)值和近似值（[`漂浮`](floating-point-types.html)/[`双倍的`](floating-point-types.html)) 数字：

-   跨平台的一致转换结果，消除了例如 Unix 与 Windows 的转换差异。

-   在以前的结果不能提供足够精度的情况下准确表示值，例如接近 IEEE 限制的值。

-   以尽可能高的精度将数字转换为字符串格式。精度`dtoa`总是与标准 C 库函数相同或更好。

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

    这`dtoa`库提供具有以下属性的转换。*`D`*用 a 表示一个值[`十进制`](fixed-point-types.html)或字符串表示，和*`F`*表示本机二进制 (IEEE) 格式的浮点数。

-   *`F`* -> *`D`*转换以尽可能高的精度完成，返回*`D`*作为产生的最短字符串*`F`*当读回并四舍五入到 IEEE 指定的本机二进制格式的最接近值时。

-   *`D`* -> *`F`*转换是这样完成的*`F`*是最接近输入十进制字符串的本机二进制数*`D`*.

    这些性质意味着*`F`* -> *`D`* -> *`F`*转换是无损的，除非*`F`*是`-inf`,`+信息`， 要么`钠`.不支持后面的值，因为 SQL 标准将它们定义为无效值[`漂浮`](floating-point-types.html)要么[`双倍的`](floating-point-types.html).

    为了*`D`*-> *`F`*-> *`D`*转换，无损的充分条件是*`D`*使用 15 位或更少的精度，不是非规范值，`-inf`,`+信息`， 要么`钠`.在某些情况下，转换是无损的，即使*`D`*具有超过 15 位的精度，但并非总是如此。

    将数值或时间值隐式转换为字符串会生成一个具有字符集和排序规则的值，该字符集和排序规则由[`字符集连接`](server-system-variables.html#sysvar_character_set_connection)和[`collat​​ion_connection`](server-system-variables.html#sysvar_collation_connection)系统变量。（这些变量通常设置为[`设置名称`](set-names.html).有关连接字符集的信息，请参阅[第 10.4 节，“连接字符集和排序规则”](charset-connection.html).)

    这意味着这样的转换会产生一个字符（非二进制）字符串（a[`字符`](char.html),[`VARCHAR`](char.html)， 要么[`长文`](blob.html)值），除非连接字符集设置为`二进制`.在这种情况下，转换结果是一个二进制字符串（a[`二进制`](binary-varbinary.html),[`变量`](binary-varbinary.html)， 要么[`长块`](blob.html)价值）。

    对于整数表达式，前面关于表达式的注释*评估*对表达式的应用有所不同*任务*;例如，在这样的声明中：


```
CREATE TABLE t SELECT integer_expr;
```

在这种情况下，由表达式产生的列中的表具有类型[`INT`](integer-types.html)要么[`大整数`](integer-types.html)取决于整数表达式的长度。如果表达式的最大长度不适合[`INT`](integer-types.html),[`大整数`](integer-types.html)改为使用。长度取自`最长长度`的价值[`选择`](select.html)结果集元数据（见[C API 基本数据结构](https://dev.mysql.com/doc/c-api/8.0/en/c-api-data-structures.html)）。这意味着您可以强制[`大整数`](integer-types.html)而不是[`INT`](integer-types.html)通过使用足够长的表达式：

```
CREATE TABLE t SELECT 000000000000000000000;
```
