Подтвердить что ты не робот

Как заказать результат спящего режима на основе определенного порядка

Мне нужно отправить запрос для извлечения значений, имеющих определенную группу символов, как показано ниже:

Позволяет сказать, что меня интересует "XX" , поэтому он должен искать любое поле, значение которого начинается с "XX" или имеет "XX" (пробел XX). Например, XXCDEF, PD XXRF и CMKJIEK XX являются действительными результатами.

У меня есть следующий запрос: возвращает правильные результаты, но мне нужно отсортировать их.  таким образом, чтобы он сначала возвращал те, у которых XX в начале, а затем другие результаты. Как показано ниже:

XXABCD
XXPLER
XXRFKF
AB XXAB
CD XXCD
ZZ XXOI
POLO XX

код

Criteria criteria = session.createCriteria(Name.class, "name")
                .add(Restrictions.disjunction()
                     .add(Restrictions.ilike("name.fname", fname + "%"))
                     .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%"))
                    )
                .setProjection(Projections.property("name.fname").as("fname"));
        List<String> names = (List<String>) criteria.list();
4b9b3361

Ответ 1

С JPQL (HQL):

select fname from Name
where upper(fname) like :fnameStart or upper(fname) like :fnameMiddle
order by (case when upper(fname) like :fnameStart then 1 else 2 end), fname

query.setParameter("fnameStart", "XX%");
query.setParameter("fnameMiddle", "% XX%");

С критериями

С Criteria это намного сложнее. Во-первых, вам нужно прибегнуть к родному SQL в предложении order. Во-вторых, вы должны привязать переменную.

public class FirstNameOrder extends Order {
    public FirstNameOrder() {
        super("", true);
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return "case when upper(FIRST_NAME) like ? then 1 else 2 end";
    }
}

Синтаксис выражения case и имя функции upper должны быть изменены в соответствии с вашей базой данных (и имя столбца, если оно отличается, конечно).

Это легко добавить к Criteria, но API не связывает параметр.

Я попытался обмануть Hibernate, передав неиспользуемую переменную в пользовательское ограничение sql, чтобы оно эффективно использовалось для переменной в предложении order by:

Criteria criteria = session.createCriteria(Name.class, "name")
   .add(Restrictions.disjunction()
      .add(Restrictions.ilike("name.fname", fname + "%"))
      .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%")))
   .setProjection(Projections.property("name.fname").as("fname"))
   .add(Restrictions.sqlRestriction("1 = 1", fname + "%", StringType.INSTANCE))
   .addOrder(new FirstNameOrder())
   .addOrder(Order.asc("fname"));

и он отлично работает.

Очевидно, что это решение не рекомендуется, и я предлагаю использовать JPQL для этого запроса.

Ответ 3

Запустите два выбора, один отфильтрован для всех строк, начинающихся с "XX", второй отфильтрован для остальных.

Ответ 4

Вы можете использовать Predicates в критериях... что-то вроде этого:

public List<Name> findByParameter(String key, String value, String orderKey)

            CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
            CriteriaQuery<Name> criteria = builder.createQuery(this.getClazz());
            Root<Name> root = criteria.from(Name.getClass());
            criteria.select(root);
            List<Predicate> predicates = new ArrayList<Predicate>();
            predicates.add(builder.equal(root.get(key), value));
            criteria.where(predicates.toArray(new Predicate[predicates.size()]));
            if (orderKey!=null  && !orderKey.isEmpty()) {
                criteria.orderBy(builder.asc(root.get(orderKey)));
            }
            result = this.entityManager.createQuery(criteria).getResultList();

        return result;
}

Ответ 5

Глупо, но это может сработать для вашего дела.

Поскольку вы получили правильный результат, вы можете просто восстановить свои результаты следующим образом:

  • выберите все результаты, начиная с XX, вы поместите их в список L1 и выполните обычную сортировку типа Collections.sort(L1);
  • для всех других результатов, сделайте то же самое, что и Collections.sort(L2) в качестве списка L2
  • Наконец, соедините их

    Список newList = новый ArrayList (L1);

    newList.addAll(L2);

Обратите внимание. Collections.sort следуют естественному упорядочению своих элементов.

Ответ 6

Если вы не хотите сортировать результат в памяти, вы можете изменить свои критерии, я покажу вам SQL

select * from table where fname like 'XX%' order by fname
union all
select * from table where fname like '% XX%' order by fname
union all
select * from table where fname like '% XX' order by fname

результат будет вашим заказом и алфавитным, а затем применить ваш фильтр.