跑一组数字和字符串混合比较,看MySQL的隐式类型转换真实会给出哪些反直觉的结果,以及它是不是真的完全没有留下任何痕迹。
代码SELECT '10' = '1e1' AS a, 10 = '10abc' AS b, 0 = 'abc' AS c, '' = 0 AS d, 1 = ' 1' AS e, 'true' = 1 AS f;
'10' = '1e1' → 0 (字符串对字符串,逐字符比较,真实不相等) 10 = '10abc' → 1 (数字对字符串,'10abc'真实转成数字10,前缀能转的部分) 0 = 'abc' → 1 ('abc'真实没有可转换的数字前缀,转成0,0=0) '' = 0 → 1 (空字符串真实转成0) 1 = ' 1' → 1 (前导空格真实被忽略) 'true' = 1 → 0 ('true'真实同样转不出数字,转成0,0≠1)
只要比较的两边有一个是数字类型,MySQL真实的规则是把字符串那一边转换成数字再比较——转换规则是"尽量读出字符串开头能构成数字的部分,读不出就当0",所以'10abc'真实变成10,'abc'和'true'真实都变成0(它们都没有能转换的数字前缀)。这也是为什么0 = 'abc'这种看起来风马牛不相及的比较,真实会返回true。
SELECT 0 = 'abc'; SHOW WARNINGS; → Warning 1292: Truncated incorrect DOUBLE value: 'abc' ← 真实有warning,但查询没有报错
每一步都是本文上面用真实查询跑出来的原始结果。
SHOW WARNINGS:确认隐式转换真实留下的痕迹