Спящий режим с нулями
Спящий режим, используемый с DB PostgreSQL при заказе desc в столбце, ставит нулевые значения выше, чем не null.
Стандарт SQL99 предлагает ключевое слово «NULLS LAST», чтобы объявить, что нулевые значения следует помещать ниже, чем не null.
Может ли поведение «NULLS LAST» быть достигнуто с использованием API критериев Hibernate?
- Индексы и порядок MySQL
- GROUP_CONCAT ORDER BY
- Лучший способ сохранить упорядоченный список в базе данных, сохраняя порядок
- MySQL 'Order By' - сортировка буквенно-цифровых символов
- Linq упорядочивает, группирует и упорядочивает по каждой группе?
- Как я могу заказать базу данных SQLITE в порядке убывания, для приложения для Android?
- Используйте собственный IComparer с Linq OrderBy
- Монгоский порядок по длине массива
- Почему смещение MYSQL выше LIMIT замедляет запрос вниз?
- Entity Framework Include OrderBy random генерирует повторяющиеся данные
- MySQL Orderby число, Nulls last
- порядок запросов mysql по нескольким пунктам
- Заказ строк по умолчанию для выбора запроса в oracle
Учитывая, что 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 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 4.2.x и 4.3.x, как упоминалось ранее.
Его можно использовать, например:
Criteria criteria = ...; criteria.addOrder( Order.desc( "name" ).nulls(NullPrecedence.FIRST) );
Hibernate v4.3 javadocs здесь меньше.
Вы можете настроить «nulls first» / «nulls last» в свойствах hibernate, чтобы по умолчанию был выбран любой критерий: hibernate.order_by.default_null_ordering=last
(или =first
).
Подробнее см. Это hibernate commit .
Вот мое обновление для classа (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 Apr 1 ’11 в 14:52
Также вы можете использовать это в JPA (hibernate):
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 are more than non-nulls», которые у нас были.
Другой вариант, если вы создаете SQL «на лету» и не используете Criteria API:
ORDER BY COALESCE (, ‘0’) [ASC | DESC]
Это работает либо для varchar, либо для числовых столбцов.
Кажется, что для этого открыт запрос на изменение / ошибка