背景
业务需要根据一个时间字段进行排序,该字段非必填,使用 mybatis 默认排序规则,会将值为 NULL 的数据排在最前面,希望升序时,值为 NULL 的数据排在最后。
实现
错误实现
由于项目使用 mybatis-plus 进行查询,最开始想到的就是使用.last()方法,但试验后发现不行,在最后拼接语句,依旧会造成 NULL 值在最后
解决方案
查看 mybatis-plus 源码,发现其底层的实现思路是


发现 wrapper 中可以直接获取这个 expression

直接模仿该方法即可,将 NULL 值排序到最后的操作,放在排序规则第一个
实现
java
/**
* 排序时,将字段column为null的数据排到最后面
* <pre>
* ORDER BY
* age DESC,
* CASE WHEN age IS NULL THEN 1 ELSE 0 END ASC
*
* </pre>
*
* @since 3.8.0.RC5
*/
private static final String ORDER_POST_NULL = "CASE WHEN {} IS NULL THEN 1 ELSE 0 END";
/**
* 排序时,将为字段column中,值为null的数据排在最后
*
* @param column 排序字段
* @return CASE 语句:CASE WHEN age IS NULL THEN 1 ELSE 0 END
* @since 3.8.0.RC5
*/
public static <T> String getOrderNullPostSql(SFunction<T, ?> column) {
return StrUtil.format(ORDER_POST_NULL, NtsWrappers.getColumnName(column));
}
/**
* 将字段column中,值为null的数据排在最后
*
* @param queryWrapper 查询条件构造器
* @param column 排序字段
* @param <T> 数据库实体类泛型
* @since 3.8.0.RC5
*/
public static <T> void orderNullPost(LambdaQueryWrapper<T> queryWrapper, SFunction<T, ?> column) {
queryWrapper.getExpression().add(ORDER_BY, () -> getOrderNullPostSql(column), ASC);
}
使用时,在调用 mybatis-plus 的排序方法前先调用 orderBullPost 方法
