在MyBatis-Plus中,通过QueryWrapper的last方法追加原生SQL片段,可实现复杂排序。例如处理gate_no字段时,使用CASEWHEN将特殊值“天”置后,再提取其中的X和YYY部分并转为数值排序,从而满足多字段组合及特殊规则的自定义需求,有效提高排序灵活性。
在使用 MyBatis-Plus 进行数据库操作时,常会遇到需要根据复杂条件排序的场景——并非简单的单字段升序或降序,而是涉及多字段、特定规则甚至特殊值处理。下面通过一个实际案例,介绍如何在 MyBatis-Plus 中实现自定义复杂排序逻辑。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
假设有一个车辆保险信息查询功能,要求按 gate_no 字段排序。该字段格式为 X-YYY,其中 X 可以是数字或特殊字符串(如“天”),YYY 为数字。排序规则:先按 X 数值排序,若 X 为“天”,则排在所有数字之后;在 X 相同的情况下,再按 YYY 数值排序。
例如:1-001、2-001、天-001、1-002,期望顺序为 1-001、1-002、2-001、天-001。仅靠 MyBatis-Plus 自带的排序方法无法满足需求,需要引入自定义 SQL 片段。
MyBatis-Plus 的 QueryWrapper 提供了丰富的查询条件构建方法,但对于复杂排序,最直接的方式是利用 last 方法追加原生 SQL 片段。下面分步骤说明。
首先,创建一个 QueryWrapper 实例。若查询模型(model)为空,直接返回空实例,避免后续处理报错。
QueryWrapperqueryWrapper = new QueryWrapper<>(); if (model == null) { return queryWrapper; }
核心排序逻辑使用 last 方法追加到 SQL 末尾。此处用 CASE WHEN 处理特殊值“天”,再用 CAST 配合 SUBSTRING_INDEX 将字符串拆分为数值,确保按数值排序而非字符串字典序。
String customOrderSql = "CASE WHEN gate_no LIKE '天-%' THEN 2 ELSE 1 END, " +
"CAST(SUBSTRING_INDEX(gate_no, '-', 1) AS UNSIGNED), " +
"CAST(SUBSTRING_INDEX(gate_no, '-', -1) AS UNSIGNED)";
queryWrapper.last("ORDER BY " + customOrderSql);
CASE WHEN gate_no LIKE '天-%' THEN 2 ELSE 1 END,将“天”开头的记录标记为2,其他为1。排序时1在前、2在后,从而将“天”的记录排到最后。SUBSTRING_INDEX(gate_no, '-', 1) 提取“-”前面的部分(即X),再用 CAST(… AS UNSIGNED) 转为无符号整数,确保按数值大小排序,而非按字符串“1”、“2”、“10”的顺序。SUBSTRING_INDEX(gate_no, '-', -1) 提取“-”后面的部分(即YYY),同样转数值排序。这样在X相同的情况下,YYY小的排在前面。实际业务中,除排序外还需根据多个字段过滤,如按车辆ID、车牌号等条件筛选。此处仅展示几个示例条件,便于理解整体结构:
queryWrapper
.eq(model.getCarId() != null && model.getCarId() != 0, "car_id", model.getCarId())
.like(StringUtils.isNotBlank(model.getLicensePlate()), "license_plate", model.getLicensePlate());
将以上步骤整合,即可得到一个完整的查询包装器构建方法:
@Override public QueryWrapperonSelectWhere(VCzInsuranceEntity model) { QueryWrapper queryWrapper = new QueryWrapper<>(); if (model == null) { return queryWrapper; } String customOrderSql = "CASE WHEN gate_no LIKE '天-%' THEN 2 ELSE 1 END, " + "CAST(SUBSTRING_INDEX(gate_no, '-', 1) AS UNSIGNED), " + "CAST(SUBSTRING_INDEX(gate_no, '-', -1) AS UNSIGNED)"; queryWrapper.last("ORDER BY " + customOrderSql); queryWrapper .eq(model.getCarId() != null && model.getCarId() != 0, "car_id", model.getCarId()) .like(StringUtils.isNotBlank(model.getLicensePlate()), "license_plate", model.getLicensePlate()); return queryWrapper; }
该方法的核心思路是利用 last 方法手写原生 SQL,将排序逻辑完全掌控在自己手中。虽然多写了几行代码,但面对“特殊值置后、多字段数值排序”这类需求,它是最清晰、最可靠的方案。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述