在不同数据库中对null字段的order by优先级有所不同,造成在一些情况下应用的排序有误。解决办法其实可以使用NULLS LAST和 NULLS FIRST来声明给数据库对NULL字段的排序,但在使用hibernate的条件查询(criteria)不支持这一特性。不过直到4.2.0.CR1,hibernate官方解决了这个问题。详细见:https://hibernate.onjira.com/browse/HHH-465
虽然官方已经解决了这个问题,但之前对此问题的一个的解决方案很值得参考,可能在日后解决问题的时候得到一定的启发。这个方案简单来说,就是在生成的SQL后,添加为SQL增加自定义的修改,所以十分日后也许十分有用。
参考 http://stackoverflow.com/questions/3683174/hibernate-order-by-with-nulls-last
1.创建一个自己的Interceptor,MyNullsFirstInterceptor
public class MyNullsFirstInterceptor extends EmptyInterceptor { private static final long serialVersionUID = -8690066766867444573L; private final Log logger = LogFactory.getLog(getClass()); private static final String ORDER_BY_TOKEN = "order by"; /* * (non-Javadoc) * * @see org.hibernate.EmptyInterceptor#onPrepareStatement(java.lang.String) */ //FIXME replace来解决不完美。并且如果没写ASC或者DESC的情况下,也会有默认的排序。 public String onPrepareStatement(String sql) { int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN); boolean isNeedFixNullFirst = orderByStart > -1; if (!isNeedFixNullFirst) { return super.onPrepareStatement(sql); } sql = StringUtils.replace(sql, " DESC ", " DESC NULLS LAST "); sql = StringUtils.replace(sql, " DESC)", " DESC NULLS LAST)"); sql = StringUtils.replace(sql, " ASC ", " ASC NULLS FIRST "); sql = StringUtils.replace(sql, " ASC)", " ASC NULLS FIRST)"); // orderByStart += ORDER_BY_TOKEN.length() + 1; // int orderByEnd = sql.indexOf(")", orderByStart); // if (orderByEnd == -1) { // orderByEnd = sql.indexOf(" UNION ", orderByStart); // if (orderByEnd == -1) { // orderByEnd = sql.length(); // } // } // String orderByContent = sql.substring(orderByStart, orderByEnd); // String[] orderByNames = orderByContent.split("\\,"); // for (int i = 0; i < orderByNames.length; i++) { // if (orderByNames[i].trim().length() > 0) { // if (orderByNames[i].trim().toLowerCase().endsWith("desc")) { // orderByNames[i] += " NULLS LAST"; // } else { // orderByNames[i] += " NULLS FIRST"; // } // } // } // orderByContent = StringUtils.join(orderByNames, ","); // sql = sql.substring(0, orderByStart) + orderByContent // + sql.substring(orderByEnd); logger.debug("--------------------"); logger.debug(sql); logger.debug("--------------------"); return super.onPrepareStatement(sql); }
注释掉的部分为原帖的解决方案,但使用后发现会报错,没详细的排查,而是采取了简单的处理方案,即看到DESC的时候直接后面添加NULLS LAST,而遇到ASC的时候反之。当然replace的那代码块一段完全可以更好的正则来实现。
也可以看到FIXME的那个注释,如果没写ASC和DESC的话,这个就完全起效没用了,但如果用criteria条件查询的话,一定会有的咯。
二,添加MyNullsFirstInterceptor到sessionFactory的xml配置内容中。
<property name="entityInterceptor"> <bean id="myNullsFirstInterceptor" class="cn.com.timekey.commons.dao.MyNullsFirstInterceptor" /> </property>
详细如:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="hibernateProperties"> <props> <!-- c3p0 ConnectPool Config begin --> <prop key="hibernate.connection.provider_class"> org.hibernate.connection.C3P0ConnectionProvider </prop> <prop key="hibernate.c3p0.minPoolSize">5</prop> <prop key="hibernate.c3p0.maxPoolSize">20</prop> <prop key="hibernate.c3p0.timeout">600</prop> <prop key="hibernate.c3p0.max_statement">100</prop> <prop key="hibernate.c3p0.acquire_increment">2</prop> <prop key="hibernate.c3p0.idle_test_period">120</prop> <prop key="hibernate.c3p0.validate">false</prop> <prop key="hibernate.c3p0.testConnectionOnCheckout"> false </prop> <prop key="hibernate.dialect">${jdbc.dialect}</prop> <!-- c3p0 ConnectionPool Config end --> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <!-- Take care of this config, affect to DB. --> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> <prop key="hibernate.jdbc.fetch_size">50</prop> <prop key="hibernate.jdbc.batch_size">30</prop> <prop key="hibernate.statement_cache.size">25</prop> </props> </property> <property name="mappingLocations"> <list> <value> classpath:/cn/com/timekey/project/po/**.hbm.xml </value> </list> </property> <property name="entityInterceptor"> <bean id="myNullsFirstInterceptor" class="cn.com.timekey.commons.dao.MyNullsFirstInterceptor" /> </property> </bean> </beans>
由于这个问题已经在hibernate4.2.0cr1中被修复了。所以也不打算进一步的优化了,至少目前是这么想。这套东西可以作为oracle和db2环境下的临时应急方案吧。(注,因为下mysql,mssql的null字段优先级默认就是最低)
相关推荐
将字符串排序为 SQL 这是一个 rust crate,用于将“排序表达式”转换为可在“ORDER BY”中使用的 SQL 表达式。 例如, -date,id将转换为date DESC NULLS LAST, id ASC NULLS LAST 。 它可用于将 HTTP 查询参数转换...
适用情况: oracle 对查询结果进行排序时,被排序的栏位存在null值,且要指定NULL值排在最前面或者最后面 关键字:Nulls First;Nulls Last 默认情况:null 默认为最大值(即:asc 升序<小–>大>,null值排在最后...
ORDER BY last_name NULLS LAST, first_name ASC; ``` 在这个例子中,如果`last_name`为空,那么这些记录将在非空的`last_name`记录之后显示,而`first_name`则按升序排列。 总之,Oracle中的排序是一个涉及广泛的...
SELECT * FROM perexl ORDER BY danwei DESC NULLS LAST; 十一、使用 DECODE 函数对 NULL 值进行处理 在 Oracle 中,可以使用 DECODE 函数对 NULL 值进行处理。例如,以下语句将对 perexl 表中的数据按照 danwei ...
8. **分页查询**:Oracle中通常使用`ROWNUM`进行分页,但要注意`ORDER BY`和`ROWNUM`的配合使用。如果先`ORDER BY`再用`ROWNUM`,可能会导致分页结果不正确。正确的做法是: ```sql select * from ( select ...
SELECT * FROM table_name ORDER BY column_name NULLS FIRST/LAST; ``` Oracle还支持多列排序,可以同时按照多个列进行排序,先按第一列排序,再按第二列排序,以此类推。例如: ```sql SELECT * FROM table_name...
NULLS FIRST`和`ORDER BY ... NULLS LAST`可以让空值出现在排序的前面或后面。在示例中,`NULLS LAST`确保空值不会打乱其他非空值的顺序,而`NULLS FIRST`则让空值排在最前。 5. **根据数据项的键排序**:`CASE`...
通过在`ORDER BY`子句中使用`NULLS LAST/FIRST`,我们可以指定空值是排在最后还是最前。例如: ```sql SELECT region_id, customer_id, SUM(customer_sales) cust_total, RANK() OVER (PARTITION BY region_id ...
本文介绍了一种基于Struts和Hibernate实现高效分页的方法,特别是在数据库不支持分页查询的情况下。通过自定义存储过程`Ture_Page`以及正确的Hibernate配置,可以显著提高系统性能,优化用户体验。这种方法不仅适用...
这里使用`PARTITION BY dept`来定义每个部门为一个独立的分区,`ORDER BY salary DESC NULLS LAST`则指定了在每个部门内部按照薪水降序排列,并将空值排在最后。 #### 五、输出结果示例 输出结果展示了每个员工的...
4. **ORDER BY NULLS LAST**:在排序时,`NULLS LAST`选项确保NULL值在排序结果的最后出现,如`ORDER BY area_code, bill_month NULLS LAST`。 5. **NVL 函数家族**:NVL函数用于处理NULL值。`NVL(a,1)`当a为NULL时...
4. **ORDER BY 子句中的 NULLS LAST**:在`ORDER BY`子句中,`NULLS LAST`选项确保`NULL`值在排序时出现在最后,例如`ORDER BY area_code, bill_month NULLS LAST`。 5. **NVL 函数家族**: - `NVL(a, b)`:如果`a...
在提供的`list_nulls.c`文件中,我们可能找到具体的实现细节,例如如何定义`hlist`结构体,如何初始化链表,以及如何遍历并处理空节点。这可能包括对特定宏的使用,比如Linux内核中的`hlist_for_each_entry`或`hlist...
Order子句则用于定义行的排序,可以包含ASC或DESC关键字,以及NULLS FIRST或NULLS LAST选项来控制NULL值的位置。Window子句更为复杂,它定义了分析函数的工作范围,可以基于行数(ROWS BETWEEN)或值范围(RANGE ...
DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal DESC NULLS LAST) AS dense_rank, ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC NULLS LAST) AS row_number FROM emp; ``` - **RANK()**:为...
nulls_for_goals
在实际项目中,例如在类`mod_gcdownload`的`get_gcdownload_datalist`方法中,可能需要根据各种条件(如日期范围、版本、合作ID等)来构造SQL查询,并结合`ORDER BY`语句对结果进行排序。在这种情况下,理解并正确...
- **语法**:`RANK() OVER (PARTITION BY <partition_by_clause> ORDER BY <order_by_clause> NULLS { FIRST | LAST })` - `PARTITION BY`子句用于将数据集分成多个分区,在每个分区内进行排名。 - `ORDER BY`子句...