运算中数据类型的转换
当一个运算符与不同类型的操作数一起使用时,将进行类型转换以使操作数兼容。一些转换是隐式发生的。例如,MySQL会根据需要自动将字符串转换为数字,反之亦然。
mysql>SELECT 1+'1'; -> 2 mysql>SELECT CONCAT(2,' test'); -> '2 test'
也可以使用该CAST()
函数将数字明确转换为字符串。该CONCAT()
函数隐式地进行转换,因为它需要字符串参数。
mysql>SELECT 38.8, CAST(38.8AS 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。无需转换。 - 如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
- 如果两个参数都是整数,则将它们作为整数进行比较。
- 如果不与数字比较,则将十六进制值视为二进制字符串。
如果参数之一是a
TIMESTAMP
或DATETIME
column,而另一个参数是常量,则在执行比较之前,该常量将转换为时间戳。这样做是为了使ODBC更友好。对于的参数,此操作未完成IN()
。为了安全起见,在进行比较时请始终使用完整的日期时间,日期或时间字符串。例如,要在BETWEEN
与日期或时间值一起使用时获得最佳结果,请使用CAST()
将值显式转换为所需的数据类型。一个或多个表中的单行子查询不被视为常量。例如,如果子查询返回要与
DATETIME
值进行比较的整数,则比较将作为两个整数进行。整数不转换为时间值。要将操作数作为DATETIME
值进行比较,请使用CAST()
将子查询值显式转换为DATETIME
。- 如果参数之一是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较;如果另一个参数是浮点值,则将参数作为浮点值进行比较。
- 在所有其他情况下,将参数作为浮点数(实数)进行比较。例如,将字符串和数字操作数进行比较,将其作为浮点数的比较。
有关将值从一种时间类型转换为另一种时间类型的信息,请参见“日期和时间类型之间的转换”。
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_nameWHERE str_col=1;
这样做的原因是,有许多不同的字符串可以转换为价值1
,例如'1'
,' 1'
或'1a'
。
浮点数与较大INTEGER
类型的值之间的比较是近似的,因为在比较之前,该整数已转换为双精度浮点,因此无法精确表示所有64位整数。例如,整数值2 53 +1无法表示为浮点数,根据平台的不同,将在浮点数比较之前将其舍入为2 53或2 53 + 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极限的值),可以精确表示值。
- 以最佳精度将数字转换为字符串格式。的精度
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
转换,用于losslessness的充分条件是,D
使用15个或更少的精确度位数,是不是反规范值,-inf
,+inf
,或NaN
。在某些情况下,即使D
精度超过15位,转换也是无损的,但并非总是如此。
将数字或时间值隐式转换为字符串会产生一个值,该值具有由character_set_connection
和collation_connection
变量决定的字符集和校验规则。(这些变量通常使用设置SET NAMES
。有关连接字符集的信息,请参见“连接字符集和校验规则”。)
这意味着,在一个字符(非二进制的)字符串这种转换的结果(一个CHAR
,VARCHAR
或LONGTEXT
值),除了在的情况下的连接的字符集被设定为binary
。在这种情况下,转换结果是一个二进制串(一个BINARY
,VARBINARY
或LONGBLOB
值)。
对于整数表达式,有关表达式运算的上述说明在表达式分配中的应用有些不同;例如,在这样的语句中:
CREATE TABLE tSELECT integer_expr;
在这种情况下,由表达式产生的列中的表具有类型INT
或BIGINT
取决于整数表达式的长度。如果表达式的最大长度不适合INT
,BIGINT
则使用。该长度取自结果集元数据的max_length
值SELECT
(请参见“ C API数据结构”)。这意味着您可以强制a BIGINT
而不是INT
使用足够长的表达式:
CREATE TABLE tSELECT 000000000000000000000;