当操作符与不同类型的操作数一起使用时,会发生类型转换,以使操作数兼容。一些转换是隐式的。例如,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
,结果为 true。不需要转换。 -
如果比较操作的两个参数都是字符串,则将它们作为字符串进行比较。
-
如果两个参数都是整数,则将它们作为整数进行比较。
-
十六进制值将被视为二进制字符串,除非与数字进行比较。
-
如果一个参数是
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'
。
浮点数和大整数类型之间的比较是近似的,因为整数被转换为双精度浮点数以进行比较,这种浮点数不能精确地表示所有64位整数。例如,整数值253 + 1不能被表示为浮点数,而是被四舍五入到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.3.4.8节,“浮点数值的问题”。
服务器包括dtoa
,一个转换库,提供了改进的字符串或DECIMAL
值和近似值(FLOAT
/DOUBLE
)之间的转换基础:
-
跨平台的一致转换结果,消除了 Unix 与 Windows 转换差异等问题。
-
准确地表示值,在以前结果不够精确的情况下,例如在 IEEE 限制附近的值。
-
将数字转换为字符串格式,以最佳可能的精度。
dtoa
的精度总是与标准 C 库函数相同或更好。
由于该库生成的转换结果在某些情况下与非 dtoa
结果不同,因此可能存在不兼容性问题。在某些情况下,应用程序可能需要调整以适应额外的精度。
该 dtoa
库提供了以下属性的转换。D
代表具有 DECIMAL
或字符串表示的值,而 F
代表浮点数的本机二进制(IEEE)格式。
-
F
->D
转换是以最佳可能的精度进行的,返回D
作为读回时最短的字符串,四舍五入到最近的本机二进制值,如 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;