Hibernate order by nulls last

时间:2010-09-10 08:30:24

标签: java hibernate null sql-order-by

Hibernate与PostgreSQL DB一起使用,当按列排序desc时,将null值设置为高于非null值。

SQL99标准提供关键字“NULLS LAST”来声明空值应该低于非空值。

使用Hibernate的Criteria API可以实现“NULLS LAST”行为吗?

7 个答案:

答案 0 :(得分:43)

此功能已在Hibernate 4.2.x和4.3.x版本中实现,如前所述。

它可以用作例如:

Criteria criteria = ...;
criteria.addOrder( Order.desc( "name" ).nulls(NullPrecedence.FIRST) );

Hibernate v4.3 javadocs不太遗漏here

答案 1 :(得分:15)

鉴于HHH-465没有修复,并且由于Steve Ebersole给出的理由不会在不久的将来得到修复,你最好的选择是使用问题所附的CustomNullsFirstInterceptor全局或专门用于更改SQL语句。

我在下面为读者发帖(Emilio Dolce的作品):

public class CustomNullsFirstInterceptor extends EmptyInterceptor {

    private static final long serialVersionUID = -3156853534261313031L;

    private static final String ORDER_BY_TOKEN = "order by";

    public String onPrepareStatement(String sql) {

        int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN);
        if (orderByStart == -1) {
            return super.onPrepareStatement(sql);
        }
        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); 
        return super.onPrepareStatement(sql);
    }

}

答案 2 :(得分:5)

您可以在hibernate属性中配置“nulls first”/“nulls last”,以便默认情况下通过任何条件调用来选择它:hibernate.order_by.default_null_ordering=last(或=first)。

有关详细信息,请参阅this hibernate commit

答案 3 :(得分:2)

这是我对班级的更新(Pascal Thivent):

for (int i = 0; i < orderByNames.length; i++) {
    if (orderByNames[i].trim().length() > 0) {
        String orderName = orderByNames[i].trim().toLowerCase();
        if (orderName.contains("desc")) {
            orderByNames[i] = orderName.replace("desc", "desc NULLS LAST");
        } else {
            orderByNames[i] = orderName.replace("asc", "asc NULLS FIRST");
        }
    }
}

这解决了问题:

  

如果sql在订购后有限制/偏移,则会中断 - Sathish 2011年4月1日14:52

此外,您还可以在JPA(休眠)中使用它:

Session session = entityManager.unwrap(Session.class);
Session nullsSortingProperlySession = null;
try {
    // perform a query guaranteeing that nulls will sort last
    nullsSortingProperlySession = session.getSessionFactory().withOptions()
        .interceptor(new GuaranteeNullsFirstInterceptor())
        .openSession();
} finally {
    // release the session, or the db connections will spiral
    try {
        if (nullsSortingProperlySession != null) {
            nullsSortingProperlySession.close();
        }
    } catch (Exception e) {
        logger.error("Error closing session", e);
    }
}

我已经在postgres上测试了它,它修复了我们所拥有的'nulls高于非nulls'问题。

答案 4 :(得分:2)

另一种变体,如果您动态创建SQL并且不使用Criteria API:

COALESCE(,'0')[ASC | DESC]

这适用于varchar或数字列。

答案 5 :(得分:1)

我们可以使用以下 Sort 参数创建 Pageable 对象:

JpaSort.unsafe(Sort.Direction.ASC, "ISNULL(column_name), (column_name)")

我们也可以准备HQL:

String hql = "FROM EntityName e ORDER BY e.columnName NULLS LAST";

答案 6 :(得分:0)