mysql ORDER BY和CASE将INT转换为CHAR?

时间:2013-03-06 06:20:23

标签: mysql casting sql-order-by

对于具有可配置排序顺序(_Sort参数)的存储过程,我使用如下代码:

    SELECT * FROM distances   
    ORDER BY 
        CASE _Sort 
            WHEN 1 THEN uid
            WHEN 2 THEN NULL
            WHEN 3 THEN name
            WHEN 4 THEN NULL
            WHEN 5 THEN distance
            WHEN 6 THEN NULL
            ELSE distance
        END ASC,
        CASE _Sort 
            WHEN 2 THEN uid
            WHEN 4 THEN name
            WHEN 6 THEN distance
            ELSE NULL
        END DESC

其中uid INT distance DOUBLE

但是如果_Sort = 1,则uid的排序方式与 CHAR 类似。

200
207
 25
  4

distance也是如此。 转换为无符号和十进制没有帮助。

ORDER BY uid ASC做正确的事,即4, 25, 200, 207

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

正如Control Flow Functions所述:

  

CASE表达式的返回类型是所有返回值的兼容聚合类型

虽然本手册没有明确说明如何确定“兼容的汇总类型”,但可以按照从Item_func_case::fix_length_and_dec()agg_result_type()item_store_type()的来源进行操作:

static Item_result item_store_type(Item_result a, Item *item,
                                   my_bool unsigned_flag)
{
  Item_result b= item->result_type();

  if (a == STRING_RESULT || b == STRING_RESULT)
    return STRING_RESULT;
  else if (a == REAL_RESULT || b == REAL_RESULT)
    return REAL_RESULT;
  else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT ||
           unsigned_flag != item->unsigned_flag)
    return DECIMAL_RESULT;
  else
    return INT_RESULT;
}

因此可以看出,如果单个返回值是一个字符串,那么整个CASE表达式的返回值也将是一个字符串。

在你的情况下,假设name是一个字符串;因此,CASE表达式返回的数据类型是一个字符串。因此,您的数值将作为字符串进行比较,从而按字典顺序排序(因此您观察到的输出)。

克服这种情况的一种方法是将所有数值填充到相等的宽度,以便按字典顺序排序将提供所需的结果:使用整数类型列的ZEROFILL属性将自动执行此操作;但是,这仍然效率很低,您可能希望考虑重新设计逻辑。

例如,您可以构建一个包含所需SQL的字符串;然后prepare and execute来自该字符串的声明:

SET @sql := CONCAT(
  'SELECT * FROM distances ORDER BY ',
  CASE _Sort
    WHEN 1 THEN 'uid ASC'
    WHEN 2 THEN 'uid DESC'
    WHEN 3 THEN 'name ASC'
    WHEN 4 THEN 'name DESC'
    WHEN 5 THEN 'distance ASC'
    WHEN 6 THEN 'distance DESC'
    ELSE 'distance ASC'
  END
);

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

答案 1 :(得分:0)

尝试此解决方案(已修改) -

SELECT * FROM distances
ORDER BY
  IF(_Sort = 1, uid, 0),
  IF(_Sort = 2, NULL, 0),
  IF(_Sort = 3, name, 0),
  IF(_Sort = 4, NULL, 0),
  ...