当运算符与不同类型的操作数一起使用时,将发生类型转换以使操作数兼容。某些转换是隐式发生的。例如,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
安全的<=>
等于比较运算符除外。对于NULL <=> NULL
,结果为真。无需转换。如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
如果两个参数都是整数,则将它们作为整数进行比较。
如果不与数字进行比较,则十六进制值将被视为二进制字符串。
如果其中一个参数是
TIMESTAMP
或DATETIME
列,而另一个参数是常量,则在执行比较之前,该常量将转换为时间戳。这样做是为了更符合 ODBC 标准。对于IN()
的参数,不会这样做。为了安全起见,在进行比较时,请始终使用完整的日期时间、日期或时间字符串。例如,要在对日期或时间值使用BETWEEN
时获得最佳结果,请使用CAST()
将值显式转换为所需的数据类型。来自一个或多个表的单行子查询不被视为常量。例如,如果子查询返回一个整数以与
DATETIME
值进行比较,则将比较作为两个整数进行。该整数不会转换为时间值。要将操作数作为DATETIME
值进行比较,请使用CAST()
将子查询值显式转换为DATETIME
。如果其中一个参数是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较;如果另一个参数是浮点值,则将参数作为浮点值进行比较。
在所有其他情况下,参数都将作为浮点数(双精度)进行比较。例如,字符串和数字操作数的比较将作为浮点数的比较进行。
有关将值从一种时间类型转换为另一种时间类型的信息,请参阅 第 13.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
类型的较大值的比较是近似的,因为在比较之前,整数会转换为双精度浮点数,而双精度浮点数不能精确地表示所有 64 位整数。例如,整数值 253 + 1 不能表示为浮点数,并且在进行浮点数比较之前,会根据平台的不同将其舍入为 253 或 253 + 2。
例如,以下比较中只有第一个比较的是相等的值,但两个比较都返回真 (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
作为最短的字符串,该字符串在读回并舍入为 IEEE 指定的原生二进制格式中的最接近值时产生F
。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
设置。有关连接字符集的信息,请参阅第 12.4 节“连接字符集和排序规则”。)
这意味着,此类转换会生成字符(非二进制)字符串(CHAR
、VARCHAR
或 LONGTEXT
值),除非连接字符集设置为 binary
。在这种情况下,转换结果为二进制字符串(BINARY
、VARBINARY
或 LONGBLOB
值)。
对于整数表达式,前面关于表达式求值的说明在表达式赋值方面有所不同;例如,在如下语句中
CREATE TABLE t SELECT integer_expr;
在这种情况下,表达式生成的列中的表具有 INT
或 BIGINT
类型,具体取决于整数表达式的长度。如果表达式的最大长度不适合 INT
,则改用 BIGINT
。长度取自 SELECT
结果集元数据的 max_length
值(请参阅C API 基本数据结构)。这意味着您可以使用足够长的表达式强制使用 BIGINT
而不是 INT
CREATE TABLE t SELECT 000000000000000000000;