Hibernate与PostgreSQL DB一起使用,而按列排序desc会将null值置为高于不为空的值。Hibernate通过空值排序最后
SQL99标准提供关键字“NULLS LAST”来声明空值应该低于非空值。
使用Hibernate的Criteria API可以实现“NULLS LAST”行为吗?
Hibernate与PostgreSQL DB一起使用,而按列排序desc会将null值置为高于不为空的值。Hibernate通过空值排序最后
SQL99标准提供关键字“NULLS LAST”来声明空值应该低于非空值。
使用Hibernate的Criteria API可以实现“NULLS LAST”行为吗?
鉴于HHH-465不是固定的,是不会得到固定在不久的将来由史蒂夫·埃伯索尔给出的理由,最好的选择是使用连接到这个问题无论是全球范围内CustomNullsFirstInterceptor
或特别是改变SQL语句。
我下面张贴的读者(学分埃米利奥·多尔切):
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);
}
}
我已经下载了最新的Hibernate版本,并没有观察到任何行为改变。你有吗?除此之外,票的正式地位仍然是开放的,尚未解决。 – mgamer 2010-09-10 09:14:02
这里是我的更新由(帕斯卡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 04年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的测试,这一点,它修复了“零点比非空高”,我们曾发行。
另一变型,如果动态地创建SQL,并且不使用标准的API:
ORDER BY COALESCE( '0')[ASC | DESC]
此作品无论是VARCHAR或数字列。
您确定,COALESCE由本地SQL中的Hibernate?Eben支持,我不确定所有的DMS都支持它吗? – 2014-04-07 16:02:19
我已经用PostgreSQL和Oracle对它进行了测试,并且,合并是Ansi SQL-92标准的一部分,所以它应该是 – 2014-04-17 20:59:36
您可以在休眠属性中配置“nulls first”/“nulls last”,以便默认情况下通过任何标准调用获取:hibernate.order_by.default_null_ordering=last
(或=first
)。详情请参阅this hibernate commit。
感谢这个解决方案在我们的案例中比其他解决方案更清洁解决方案;系统将始终以相同的方式运行,而无需更改代码。 – 2017-08-01 18:20:16
漂亮的解决方案,我没有想过拦截器,谢谢!如果有人想使用它,你需要将这一行添加到你的persistence.xml文件中: –
mgamer
2010-09-10 12:13:47
如果SQL在订购后有限制/偏移,这会中断 – Sathish 2011-04-01 14:52:47
哇,Hibernate JIRA在** 2005中打开** – atrain 2011-07-26 15:10:06