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