列= char(1),也= char(0)

时间:2019-05-23 10:03:29

标签: character-encoding mysql-5.7

我们有一个表,其中包含一列foo

show create table显示`foo` bit(1) DEFAULT b'0',因此该列应包含binary strings的第0和第1个字符。

select ascii(foo),
ord(foo),
foo=char(1),
foo=char(0),
char(1)=char(0)
from table_name
group by 1,2,3,4,5

收益

ascii(foo)   ord(foo)   foo=char(1)   foo=char(0)   char(1)=char(0)
         0          0             1             1                 0
         1          1             0             0                 0

我希望它会产生作用

ascii(foo)   ord(foo)   foo=char(1)   foo=char(0)   char(1)=char(0)
         0          0             0             1                 0
         1          1             1             0                 0

有人可以解释发生了什么吗?


Nor仅限于select子句。它也发生在where子句中:select distinct ascii(foo) from table_name where foo=char(0)select distinct ascii(foo) from table_name where foo=char(1)都只返回0。


select @@version
5.7.21-20-57-log

1 个答案:

答案 0 :(得分:0)

您是隐式打字的受害者

MySQL认为将位域列中的值视为integer,并向CHAR(1)执行隐式类型转换以进行比较。 这是MySQL实际执行的步骤:

SELECT `foo` = CHAR(1)             -- Need to cast incompatible data types
SELECT 0 = CHAR(1)                 -- Bitfield is treated as integer
SELECT 0 = CAST(CHAR(1) AS INT)    -- char 0x01 gets cast to integer
SELECT 0 = 0                       -- result: 1 (boolean TRUE for MySQL)

但是隐式类型转换取决于数据。由于很难检测到,因此可以快速导致意外结果。例如:

SELECT `foo` = CHAR(49)            -- Need to cast incompatible data types
SELECT 0 = CHAR(49)                -- Bitfield is treated as integer
SELECT 0 = CAST(CHAR(49) AS INT)   -- char 0x31 gets cast to integer
SELECT 0 = CAST("1" AS INT)        -- but: char 0x31 equals "1"
SELECT 0 = 1                       -- result: 0 (boolean FALSE for MySQL)

为什么会这样?数字类型是位域和(二进制)字符串都可以与使用相等运算符进行比较的唯一一种类型。因此,位域列将从castinteger

  

在数字上下文中,MySQL将位文字视为整数。

还需要将角色强制转换为these rules之后的integer。令人惊讶的是,为了将二进制字符转换为整数,MySQL似乎首先将其转换为常规字符,如下所示:

SELECT CAST(CAST(CHAR(49) AS CHAR) AS INT)   -- result 1

MySQL在这里必须执行两次隐式类型转换,因为:

SELECT CHAR(49)                              -- result 0x31

在这里,CHAR函数返回不带任何编码的二进制char,但是仅当可以使用编码解释字符时,才可以强制转换为integer。通过CHAR(49)获得的结果可能与我与MySQL的连接的编码设置有关。