简体   繁体   中英

My custom order by in criteria query/jpql

Is it possible to do my custom order by using criteria query or jpql in Java? In my table, I have a column - number type(for now, this column includes numbers such as 1 , 2 , 3 , 5 , 10 ). I would like to sort result in this order 2 , 5 , 1 , 10 , 3 .

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<MyEntity> cq = cb.createQuery(MyEntity.class);
Root<MyEntity> root = cq.from(MyEntity.class);

cq.select(root);
cq.where(cb.equal(root.get("someMyFields"), "myExpectedFieldValue"));
cq.orderBy(cb.asc(root.get("myNumberField"))); // how can I sort result in this order 2, 5, 1, 10, 3?

TypedQuery<MyEntity> query = em.createQuery(cq);
query.setFirstResult(0);
query.setMaxResults(200);

return query.getResultList();

How can I do it?

You have to use a CASE expression in your ORDER BY clause to implement this kind of"sort indirection" . In SQL and JPQL, this would be:

ORDER BY CASE myNumberField 
  WHEN 2  THEN 1
  WHEN 5  THEN 2
  WHEN 1  THEN 3
  WHEN 10 THEN 4
  WHEN 3  THEN 5
          ELSE 6
END

With the criteria API, using CriteriaBuilder.selectCase()

cq.orderBy(
  qb.selectCase(root.get("myNumberField"))
    .when(qb.literal(2), qb.literal(1))
    .when(qb.literal(5), qb.literal(2))
    .when(qb.literal(1), qb.literal(3))
    .when(qb.literal(10), qb.literal(4))
    .when(qb.literal(3), qb.literal(5))
    .otherwise(qb.literal(6))
    .getExpression()
    .asc());

Of course, a much better solution is to normalise these values in a separate table that you can join just for the ordering:

SELECT *
FROM t
JOIN orderings o ON t.myNumberField = o.myNumberField
ORDER BY o.orderDefinition

You can also use custom ordering with CriteriaQuery by using a special field in your database bean:

// this is used for obtaining an arbitrary ordering by statuses
@Formula(value="(CASE status\n" +
        "           WHEN 'DELETED'::text THEN 1\n" +
        "           WHEN 'UPDATED'::text THEN 2\n" +
        "           WHEN 'SUBMITTED'::text THEN 3\n" +
        "           ELSE 10\n" +
        "           END)")
private int statusPriority;

You can use the statusPriority as a regular sorting field through the Pagination object. The resulting query will contain something like:

order by (CASE quotationv0_.status
           WHEN 'DELETED'::text THEN 1
           WHEN 'UPDATED'::text THEN 2
           WHEN 'SUBMITTED'::text THEN 3
           ELSE 10
           END) asc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM