使用" ORDER BY CASE"排序结果不使用主索引

时间:2014-07-17 14:04:51

标签: mysql sql innodb

我正在尝试使用以下查询进行排序:

SELECT * FROM client 
ORDER BY 
CASE $desired_colum_to_order
   WHEN 'id' then `id`
   WHEN 'name' then `name`
   ELSE `id`
END
ASC

问题是此查询将ID作为字符串列进行排序,但它是整数主键

结果按此顺序排列: 10,11,12,13,5,6,7,8,9

如果我执行以下查询,MySQL会正确排序:

SELECT * FROM client 
ORDER BY 
id
ASC

现在结果按正确顺序排列: 5,6,7,8,9,10,11,12,13

有人可以解释一下,为什么MySQL这样排序,如果两个查询中的列相同吗?

提前致谢!

5 个答案:

答案 0 :(得分:1)

您可以将order by拆分为不同的条件:

SELECT *
FROM client 
ORDER BY (CASE WHEN $desired_colum_to_order = 'id' then id END) ASC,
         (CASE WHEN $desired_colum_to_order = 'name' then name END) ASC,
         id ASC

这是有效的,因为case语句不匹配所有返回NULL,没有订单。如果没有匹配,那么最终的id将是使用的那个。不同case语句的优点是每列都是“类型”安全的。此外,您可以使用逻辑来制作一些DESC而不是ASC

答案 1 :(得分:1)

问题是CASE表达式变成了字符串,因为该数据类型是MySQL发现的最常见的数据类型。

一个选项是将case语句拆分为所有可用的列,如下所示:

ORDER BY
  CASE $orderColumn = 'id' THEN id ELSE 0 END
  , CASE $orderColumn = 'name' THEN name ELSE '' END

另一种选择是像这样对数字字段进行zerofill:

ORDER BY
CASE $desired_colum_to_order
   WHEN 'id' then LPAD(CONVERT(`id`,VARCHAR(20)),20,'0')
   WHEN 'name' then `name`
   ELSE `id`
END

或者(我认为这是最好的选择):在您的应用程序中构建查询以动态添加所需的ORDER BY子句

答案 2 :(得分:1)

您的个案陈述:

CASE $desired_colum_to_order
    WHEN 'id' then `id`
    WHEN 'name' then `name`
    ELSE `id`
END

是字符串类型的表达式 - >串。唯一的选择是字符串 - > int,但是应该如何将name解释为int?你可以做的是将你的比较分成两部分:

ORDER BY CASE $desired_colum_to_order WHEN 'name' then `name` else '' end
       , CASE $desired_colum_to_order WHEN 'id' then `id` else 0 end

第一个CASE是表达式字符串 - > string,第二个是表达式字符串 - > INT。不相关的CASE会将所有值映射到该类型的标识元素,因此不会影响排序。

答案 3 :(得分:0)

CASE将结果评估为字符串。要获得所需的结果,您可以尝试:

SELECT * 
FROM client 
ORDER BY 
  CASE $desire_column_to_order
    WHEN 'name' THEN `name`
    ELSE 0
  END ASC, 
  `id` ASC

答案 4 :(得分:0)

问:有人可以解释一下为什么MySQL会这样订购吗?

MySQL是"订购"基于ORDER BY子句中表达式结果的行。

您在ORDER BY子句中提供了CASE表达式。该表达式返回单个数据类型。在这种情况下,表达式似乎返回 VARCHAR ,可能基于name列的数据类型。

优化器不够智能"找出'id'关键字后面的字符串文字CASE 总是与第一个'id'后面的字符串文字WHEN匹配。你看到了,但优化器没有。

你读了那个表达式,你看到第一个WHEN将匹配每一行,表达式总是返回id,表达式永远不会返回name

您认为这等同于指定ORDER BY id

但是优化器并没有这样看待它。它将name视为可能的返回值,并且它基于"工作的数据类型"对于所有可能的返回值。在这种情况下,看起来它确定VARCHAR是要返回的适当数据类型。

如果CASE表达式中的返回数据类型为整数,则行将按升序数值排序。

但MySQL仍然无法使用索引按顺序返回行,它仍然会执行"使用filesort"操作,因为行仍然按表达式的结果排序,而不是列。