对于具有可配置排序顺序(_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
有什么想法吗?
答案 0 :(得分:1)
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),
...