MySQL Order By不适用于Concat(枚举)

时间:2013-09-25 14:23:13

标签: mysql sorting character-encoding enums concat

目前,我们对枚举字段中MySQL的排序顺序存在一个相互关联的问题。字段枚举条目已按我们想要的顺序排序。为了保存,我们在它周围添加了一个CONCAT,因此它将被转换为char并按字母顺序排序,正如MySQL-reference(MySQL Reference - Enum

所建议的那样
  

确保通过编码ORDER BY CAST(col AS CHAR)或ORDER BY CONCAT(col)对列进行词法排序而不是索引编号。

但这并没有产生预期的结果,所以我们开始进一步调查。似乎order by语句对enum和concat函数的组合不起作用。我写了下面的示例脚本,它应该表明我的观点:

CREATE TABLE test (
  `col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO test
VALUES ('b'), ('c'), ('a');

SELECT * FROM test; -- b, c, a
SELECT * FROM test ORDER BY col1 ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS CHAR) ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS BINARY) ASC; -- a, b, c
SELECT * FROM test ORDER BY CONCAT(col1) ASC; -- b, c, a - This goes wrong

我目前怀疑整理/编码存在某种问题,但我不确定。我的数据库默认编码也是utf8。 MySQL版本是5.6.12但它似乎可以用MySQL 5.1重现。存储引擎是MyIsam,但它也与内存引擎一起发生。

任何帮助都将不胜感激。

更新:

因为看起来问题只出现在MySQL 5.6和列的整理中。使用第一个CREATE TABLE语句,查询可以正常工作。

CREATE TABLE test (
  `col1` enum('a','b','c') COLLATE utf8_general_ci DEFAULT NULL
)

第二个他们没有。

CREATE TABLE test (
  `col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
)

表和/或数据库的排序规则似乎不会影响查询。可以在此SQL Fiddle

中测试查询

2 个答案:

答案 0 :(得分:2)

很奇怪,它适用于这个小提琴。你有触发器吗?

http://sqlfiddle.com/#!2/0976a/2

但是,在5.6中出现了问题:

http://sqlfiddle.com/#!9/0976a/1

可能是Mysql错误。

此外,如果您以“正确”顺序输入枚举中的值,则可以正常工作:

http://sqlfiddle.com/#!9/a3784/1

在文档中:

  

ENUM值根据其索引号进行排序,这取决于   枚举成员在列中列出的顺序   规格。例如,'b'在'a'之前为ENUM排序('b','a')。

答案 1 :(得分:0)

根据document

Handling of Enumeration Literals部分下,它声明:

  

如果将数字存储到ENUM列中,则该数字将被视为   索引到可能的值,并且存储的值是   具有该索引的枚举成员。 (但是,这不起作用   LOAD DATA,将所有输入视为字符串。)如果数值为   引用,如果没有匹配,它仍然被解释为索引   枚举值列表中的字符串。由于这些原因,事实并非如此   建议定义具有外观枚举值的ENUM列   喜欢数字,因为这很容易让人感到困惑。   例如,以下列的枚举成员的字符串值为“0”,“1”和“2”,但数字索引值为1,2和3:

 numbers ENUM('0','1','2')
  

如果存储2,则将其解释为   索引值,并变为'1'(索引为2的值)。如果你存储   '2',它匹配枚举值,因此它存储为'2'。如果你   存储'3',它与任何枚举值都不匹配,因此它被处理   作为索引并变为'2'(索引为3的值)。

mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1       |
| 2       |
| 2       |
+---------+

在你的情况下:

INSERT INTO test
VALUES ('2'), ('3'), ('1');

“2”的索引值为2,“3”为3,“1”为1。 因此输出为2,3,1