背景:
对于新闻排行榜中的hot_value 属性定义的时候使用了Varchar类型,代码排序时,往往是乱的:
待排序数据:1,2,3,40,300,1000
希望排序为:1000,300,40,3,2,1
结果排序为:40,300,3,2,1000,1
解决方案:
SQL:
order by length(hot_value) desc, hot_value desc;
order by CONVERT(hot_value, UNSIGNED) desc
order by CAST(hot_value as UNSIGNED) desc
order by hot_value + 0 desc
以上都可以达到如下结果:
Mybatis Plus:
List<T> list = xxxService.list(new QueryWrapper<T>().orderByDesc("length(hot_value) DESC,(hot_value)"));
注:一定要在第一个条件后也手动写上排序规则,否则orderByDesc只会对最后一个条件追加生效!!
其他sql的方式相同写法嵌套即可。
延伸问题:
如果需要排序的属性有中文怎么办?
待排序数据:中文_1,中文_2,中文_3,中文_40,中文_300,中文_1000
注:这里只是举例说明,'中文_'可以是任意的中文,而需求是按照后边的数字排序
REGEXP_SUBSTR函数
在MySQL 8.0及以上版本中,我们可以使用 REGEXP_SUBSTR()
函数来提取字符串中的数字部分。这个函数允许我们使用正则表达式来指定我们想要匹配的模式。在这个例子中,我们使用正则表达式 \\d+
来匹配一个或多个数字。
ORDER BY CAST(REGEXP_SUBSTR(hot_value, '\\d+') AS UNSIGNED);
可能有人质疑,使用函数排序会有影响性能等问题。我们要灵活根据线上具体的情况,不同问题不同的解决方案,这里仅仅是一种解题思路。
你也可以尝试修改数据库 varchar为 int类型,如果你可以直接操作线上数据库;或者数据库几百万数据,公司愿意让你动的前提下。