对于具有可配置排序顺序(_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,距离
为DOUBLE。
但是如果 _Sort = 1,uid
的排序就像 CHAR 一样,例如
200
207
25
4
对于距离
也是如此。
转换为无符号和十进制没有帮助。
ORDER BY uid ASC
做正确的事情,即 4, 25, 200, 207
有什么想法吗?
最佳答案
如 Control Flow Functions 下所述:
The return type of a
CASE
expression is the compatible aggregated type of all return values
虽然手册没有明确记录如何确定“兼容聚合类型”,但可以遵循 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;
关于mysql ORDER BY 和 CASE 将 INT 转换为 CHAR?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15240355/