MySQL奇怪的行为用逗号分隔的数字列表

Dal*_*ley 9 mysql implicit-conversion

我有一个非常复杂的问题,但我把它缩小到这个,首先,让我给你一些测试数据:

运行这个:

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

INSERT INTO test (value) VALUES
(1),
('1'),
('1,2'),
('3');
Run Code Online (Sandbox Code Playgroud)

现在运行此查询:

SELECT * FROM test WHERE value = 1;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我希望只获得前两行,其中值作为数字1或'1'字符输入,但由于某种原因,这是我得到的:

1, 1
2, 1
3, 1,2
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么我得到第三排?

注意:这是我的mysql版本:5.6.28-0ubuntu0.14.04.1

此外,我已经通过使用FIND_IN_SET解决了我的原始问题,并且我知道将逗号分隔的列表类型结构放在一起并不是一个好主意,也就是说,它应该首先使用连接表来完成.不幸的是,我在一个非常庞大的系统中工作,并且目前这种改变是不切实际的.

我只是对这种特定行为发生的原因感兴趣.

spe*_*593 9

获得第三行的原因是MySQL执行的隐式数据类型转换.您的查询在WHERE子句中具有谓词(条件)

  WHERE value = 1
Run Code Online (Sandbox Code Playgroud)

在等式比较运算符的右侧(等号),我们有一个数字文字.在左侧,我们有一个数据类型为TEXT的列.

MySQL不可能对这两种不同的数据类型进行比较.

因此,MySQL将一侧或另一侧转换为兼容的类型,因此可以执行比较.在这种情况下,MySQL正在将列中的值转换为数字,因此它与数字文字进行比较.

由于看上去是什么样的演示,我们可以添加一个零(迫使MySQL的做了转换),并在SELECT表现出的结果.

 SELECT t.value, t.value + 0 FROM test t

 t.value  t.value + 0
 -------  -----------
 1                  1
 1                  1
 1,2                1
 3                  3
Run Code Online (Sandbox Code Playgroud)

它在MySQL参考手册的某处记录,MySQL如何进行转换.有可能错误地说明手册所说的内容:MySQL从左到右逐个字符地读取字符串,直到它遇到无法再转换为数字的字符.

如果是字符串'1,2',那恰好是逗号字符.这就是MySQL停止的地方.因此,转换返回数值1.您应该指出其他数据库会在尝试将该字符串转换为数字时抛出错误.但MySQL不会抛出错误或警告.

参考:表达式评估中的类型转换 http://dev.mysql.com/doc/refman/5.7/en/type-conversion.html

基本上,查询中的谓词等同于指定:

   WHERE value + 0 = 1
Run Code Online (Sandbox Code Playgroud)

这会强制将列的内容转换value为数字,然后与数字文字进行比较.

这就是返回第三行的原因.

要获得不同的结果,请考虑与字符串文字进行比较

   WHERE value = '1'
Run Code Online (Sandbox Code Playgroud)