【问题标题】:MySQL Order By doesn't work on Concat(enum)MySQL Order By 不适用于 Concat(enum)
【发布时间】:2013-10-01 04:51:21
【问题描述】:

目前我们有一个关于 MySQL 在枚举字段中的排序顺序的有趣问题。字段枚举条目已按我们想要的顺序排序。为了节省起见,我们在其周围添加了一个 CONCAT,因此它将被转换为 char 并按字母顺序排序,正如 MySQL 参考 (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进行测试

【问题讨论】:

  • 只是一个小信息:我目前正在使用 MariaDB 10.3.11,并且该错误在那里无法重现。

标签: mysql sorting character-encoding enums concat


【解决方案1】:

奇怪,它在这个小提琴中起作用。你有触发器还是什么?

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

但是,在 5.6 中出现问题:

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

可能是Mysql的错误。

更多,如果你以“正确”的顺序输入枚举中的值,它会起作用:

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

在文档中:

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

【讨论】:

  • 目前我倾向于认为这是您所说的 MySQL 错误。如果我在接下来的几天内没有做出其他解释,我会尝试将其报告为错误。
【解决方案2】:

根据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'。如果你 store '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

【讨论】:

  • 好的,为了让我的观点更清楚,我调整了样本值。如果您使用“a”、“b”和“c”作为枚举值,也会出现同样的问题。我知道枚举的值是根据定义中的顺序排序的。这正是我首先添加 CONCAT 的原因。
  • 你能检查一下你的服务器和数据库的字符集吗?因为它对我来说很好。这是SqlFiddle
  • 看起来问题仅在使用 UTF8_bin 时出现。我尝试使用 UTF8_bin 创建表,然后使用 UTF8_general_ci 进行排序,效果很好。这是SQLFiddle
猜你喜欢
  • 1970-01-01
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多