我的自定义订单符合标准 query/jpql
My custom order by in criteria query/jpql
是否可以在 Java 中使用条件查询或 jpql 来执行自定义订单?在我的 table 中,我有一列 - 数字类型(目前,此列包括 1
、2
、3
、5
、10
).我想按 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();
我该怎么做?
您必须在 ORDER BY
子句中使用 CASE
表达式来实现这种 "sort indirection"。在 SQL 和 JPQL 中,这将是:
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
使用条件 API,使用 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());
当然,一个更好的解决方案是在单独的 table 中规范化这些值,您可以加入其中只是为了排序:
SELECT *
FROM t
JOIN orderings o ON t.myNumberField = o.myNumberField
ORDER BY o.orderDefinition
您还可以通过在数据库 bean 中使用特殊字段来使用 CriteriaQuery 的自定义排序:
// 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;
您可以通过Pagination 对象将statusPriority 用作常规排序字段。结果查询将包含如下内容:
order by (CASE quotationv0_.status
WHEN 'DELETED'::text THEN 1
WHEN 'UPDATED'::text THEN 2
WHEN 'SUBMITTED'::text THEN 3
ELSE 10
END) asc
是否可以在 Java 中使用条件查询或 jpql 来执行自定义订单?在我的 table 中,我有一列 - 数字类型(目前,此列包括 1
、2
、3
、5
、10
).我想按 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();
我该怎么做?
您必须在 ORDER BY
子句中使用 CASE
表达式来实现这种 "sort indirection"。在 SQL 和 JPQL 中,这将是:
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
使用条件 API,使用 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());
当然,一个更好的解决方案是在单独的 table 中规范化这些值,您可以加入其中只是为了排序:
SELECT *
FROM t
JOIN orderings o ON t.myNumberField = o.myNumberField
ORDER BY o.orderDefinition
您还可以通过在数据库 bean 中使用特殊字段来使用 CriteriaQuery 的自定义排序:
// 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;
您可以通过Pagination 对象将statusPriority 用作常规排序字段。结果查询将包含如下内容:
order by (CASE quotationv0_.status
WHEN 'DELETED'::text THEN 1
WHEN 'UPDATED'::text THEN 2
WHEN 'SUBMITTED'::text THEN 3
ELSE 10
END) asc