当运算符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。有些转换是隐式发生的。例如,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
返回为最短的字符串,该字符串在读回时会产生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
设置。有关连接字符集的信息,请参见 第 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;