12.2 table 达式评估中的类型转换
当一个运算符与不同类型的操作数一起使用时,将进行类型转换以使操作数兼容。一些转换是隐式发生的。例如,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
,结果为 true。无需转换。 -
如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
-
如果两个参数都是整数,则将它们作为整数进行比较。
-
如果不与数字比较,则将十六进制值视为二进制字符串。
-
如果参数之一是TIMESTAMP或DATETIME列,而另一个参数是常量,则在执行比较之前,该常量将转换为时间戳。这样做是为了使 ODBC 更友好。 IN()的自变量未完成此操作。为了安全起见,在进行比较时,请始终使用完整的日期时间,日期或时间字符串。例如,为了在将BETWEEN与日期或时间值一起使用时获得最佳结果,请使用CAST()将值显式转换为所需的数据类型。
一个或多个 table 中的单行子查询不视为常量。例如,如果子查询返回要与DATETIME值进行比较的整数,则比较将作为两个整数进行。整数不转换为时间值。要将操作数作为DATETIME值进行比较,请使用CAST()将子查询值显式转换为DATETIME。
-
如果参数之一是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较;如果另一个参数是浮点值,则将参数作为浮点值进行比较。
-
在所有其他情况下,将参数作为浮点数(实数)进行比较。例如,将字符串和数字操作数进行比较,将其作为浮点数的比较。
有关将值从一种时间类型转换为另一种时间类型的信息,请参见第 11.2.8 节“日期和时间类型之间的转换”。
JSON 值的比较分为两个级别。比较的第一级基于比较值的 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'
。
浮点数与INTEGER
类型的大值之间的比较是近似的,因为在比较之前该整数已转换为双精度浮点,不能完全 table 示所有 64 位整数。例如,整数值 253 1 不能 table 示为浮点数,根据平台的不同,将在浮点数比较之前将其舍入为 253 或 253 2.
为了说明这一点,仅以下比较中的第一个比较比较相等的值,但是两个比较都返回 true(1):
mysql> SELECT '9223372036854775807' = 9223372036854775807;
-> 1
mysql> SELECT '9223372036854775807' = 9223372036854775806;
-> 1
当发生从字符串到浮点的转换以及从整数到浮点的转换时,它们不一定以相同的方式发生。 CPU 可以将整数转换为浮点数,而在涉及浮点乘法的运算中,将字符串逐位转换字符串。同样,结果可能会受到诸如计算机体系结构或编译器版本或优化级别等因素的影响。避免此类问题的一种方法是使用CAST(),这样就不会将值隐式转换为浮点数:
mysql> SELECT CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806;
-> 0
有关浮点比较的更多信息,请参见第 B.4.4.8 节“浮点值的问题”。
服务器包含dtoa
,该转换库为改进字符串或DECIMAL值与近似值(FLOAT/DOUBLE)数字之间的转换提供了基础:
-
跨平台的转换结果保持一致,从而消除了 Unix 与 Windows 的转换差异。
-
如果结果先前无法提供足够的精度,例如对于接近 IEEE 极限的值,则可以准确 table 示值。
-
以最佳精度将数字转换为字符串格式。
dtoa
的精度始终与标准 C 库函数的精度相同或更高。
由于此库产生的转换在某些情况下与非dtoa
结果不同,因此依赖先前结果的应用程序中可能会出现不兼容的情况。例如,依赖于先前转换的特定确切结果的应用程序可能需要进行调整以适应更高的精度。
dtoa
库提供具有以下属性的转换。 * D
table 示具有DECIMAL或字符串 table 示形式的值, F
*table 示本机二进制(IEEE)格式的浮点数。
-
F
*-> *D
转换的精度最高,回读时返回D
为产生F
*的最短字符串,并按 IEEE 指定的本机二进制格式舍入到最接近的值。
-
D
*-> *F
进行转换,使得F
是最接近 Importing 十进制字符串D
*的本机二进制数字。
这些属性 table 示* 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设置。有关连接字符集的信息,请参见第 10.4 节“连接字符集和排序规则”。)
这意味着,除非将连接字符集设置为binary
,否则这种转换会导致字符(非二进制)字符串(CHAR,VARCHAR或LONGTEXT值)。在这种情况下,转换结果是二进制字符串(BINARY,VARBINARY或LONGBLOB值)。
对于整数 table 达式,关于 table 达式* evaluation 的上述说明在 table 达式 assignment *上有所不同;例如,在这样的语句中:
CREATE TABLE t SELECT integer_expr;
在这种情况下,取决于整数 table 达式的长度,由 table 达式产生的列中的 table 的类型为INT或BIGINT。如果 table 达式的最大长度不适合INT,则使用BIGINT。该长度取自SELECT结果集元数据的max_length
值(请参见第 27.7.4 节“ C API 数据结构”)。这意味着您可以使用足够长的 table 达式来强制BIGINT而不是INT:
CREATE TABLE t SELECT 000000000000000000000;