解决oracle根据字段类型为字符串(中间包含数字)按顺序排序问题

本文介绍了一种使用SQL进行复杂排序的方法,包括如何利用正则表达式和数字转换来实现多条件排序。此外,还提供了HQL和SQL中进行类型转换的实用语法。

select p.attribute1_,p.attribute2_,p.* from app_pay_payment p order by p.attribute1_,regexp_substr(p.attribute2_,'[^0-9]+'),to_number(regexp_substr(p.attribute2_,'[0-9]+'))

 

上面方法可能有些复杂 ,也可以直接用下面方法

 

HQL写法:cast(对象属性 as long)

SQL写法:cast(字段名 as number)

你遇到的问题非常典型: > `orderDetail.itemNo` 是 **字符串类型(String)**,但存储的是数字(如 `"1"`, `"2"`, ..., `"10"`), > 直接用 `orderDetail.itemNo asc` 排序会按字典序排,结果是: > > ``` > 1, 10, 11, ..., 2, 20, 3, ... > ``` > > ❌ 不符合业务逻辑! 而你需要的是 **数值排序(Numerical Sort)**,即: ``` 1, 2, 3, ..., 10, 11, 20 ``` 由于你在使用 Oracle 数据库,并且字段是字符串,**必须在数据库层面调用 `TO_NUMBER()` 函数进行转换排序**。 --- ## ✅ 解决方案:改用 **原生 SQL 查询(Native SQL)** 因为 HQL **不支持直接调用数据库函数如 `TO_NUMBER()`**,除非你扩展方言或使用 `@Formula`,但这些方式复杂且易出错。 所以最简单、最可靠的方式是:👉 **切换为 Native SQL 查询** --- ### ✅ 正确代码实现(使用 Hibernate 原生 SQL) ```java String nativeSql = "SELECT od.* " + "FROM ORDER_DETAIL od " + "INNER JOIN ORDERS o ON od.ORDER_NO = o.ORDER_NO AND od.CREATED_BY_COMPANY = o.CREATED_BY_COMPANY " + "WHERE od.DEL_FLAG = 0 " + " AND od.ORDER_NO != 'New' " + " AND o.DEL_FLAG = 0 " + " AND o.RELEASE_STATUS = 'Close' " + "ORDER BY o.CREATED_DATE DESC, TO_NUMBER(od.ORDER_ITEM_INDEX) ASC"; Query query = getSession().createSQLQuery(nativeSql) .addEntity(OrderDetail.class); // 映射结果到 OrderDetail 实体 List<OrderDetail> result = query.list(); ``` --- ### 🔍 关键说明 | 部分 | 说明 | |------|------| | `INNER JOIN ORDERS o` | 替代原来的 `EXISTS` 子查询,更高效也更容易写排序逻辑 | | `ON od.ORDER_NO = o.ORDER_NO AND ...` | 多条件关联,确保公司隔离正确 | | `TO_NUMBER(od.ORDER_ITEM_INDEX)` | Oracle 函数,将字符串转为数字排序 ✅ | | `o.CREATED_DATE DESC` | 主订单创建时间倒序 —— 最新订单整体靠前 | | `.addEntity(OrderDetail.class)` | 自动把查询结果映射成你的实体对象 | --- ## ✅ 注意事项 ### 1. 表名和列名大小写问题OracleOracle 默认表名/列名是 **大写的**。如果你的建表语句用了双引号小写,则需调整。 ✅ 确保: - 表名:`ORDER_DETAIL`, `ORDERS` - 列名:`ORDER_ITEM_INDEX`, `CREATED_DATE`, `DEL_FLAG`, `RELEASE_STATUS`, `ORDER_NO`, `CREATED_BY_COMPANY` ### 2. 如果表名是小写的(比如通过 JPA 自动生成),要用双引号: ```sql "order_detail" -> "\"order_detail\"" ``` 但一般生产环境都是大写,无需加引号。 --- ## ✅ 可选增强:带参数查询(防注入) 如果你有搜索条件(如 orderNo 模糊查询),可以加上参数: ```java String nativeSql = "SELECT od.* " + "FROM ORDER_DETAIL od " + "INNER JOIN ORDERS o ON od.ORDER_NO = o.ORDER_NO AND od.CREATED_BY_COMPANY = o.CREATED_BY_COMPANY " + "WHERE od.DEL_FLAG = 0 " + " AND od.ORDER_NO != 'New' " + " AND o.DEL_FLAG = 0 " + " AND o.RELEASE_STATUS = 'Close' " + " AND (:orderNo IS NULL OR od.ORDER_NO LIKE :orderNo) " + "ORDER BY o.CREATED_DATE DESC, TO_NUMBER(od.ORDER_ITEM_INDEX) ASC"; Query query = getSession().createSQLQuery(nativeSql) .addEntity(OrderDetail.class); if (StringUtils.isNotBlank(searchOrderForm.getOrderNo())) { query.setString("orderNo", "%" + searchOrderForm.getOrderNo() + "%"); } else { query.setParameter("orderNo", null); } List<OrderDetail> result = query.list(); ``` --- ## ✅ 替代方案(不推荐):HQL + Formula 虚拟字段 你可以给 `OrderDetail` 实体加一个虚拟属性: ```java @Formula("TO_NUMBER(ORDER_ITEM_INDEX)") private Integer itemNoAsNumber; ``` 然后在 HQL 中排序: ```java order by (select o.createdDate from Order o where ...) desc, orderDetail.itemNoAsNumber asc ``` ⚠️ 缺点: - 多余字段影响性能; - 插入/更新可能异常; - 不适用于所有场景; 所以不如原生 SQL 干净利落。 --- ## ✅ 总结 | 方案 | 是否推荐 | 说明 | |------|----------|------| | ❌ HQL + `TO_NUMBER(...)` | 否 | HQL 不支持原生函数 | | ❌ HQL + 字符串排序 | 否 | `"10"` < `"2"`,错误顺序 | | ✅ Native SQL + `TO_NUMBER()` | ✅✅✅ 强烈推荐 | 简单、高效、可控 | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值