What are the alternatives to using an ORDER BY in a Subquery in the JPA Criteria API?
请考虑以下两个表:
其中
假设我们要查询所有状态为"新"的项目。 我提出的Sql查询是:
1 2 3 4 5 6 | SELECT q.id_project FROM status q WHERE q.status_name like 'new' AND q.id IN ( SELECT TOP 1 sq.id from status sq WHERE q.id_project = sq.id_project ORDER BY sq.id DESC ) |
我正在尝试使用Criteria API复制以上查询,并且我注意到CriteriaQuery类具有方法
到目前为止,我提出的条件查询是:
1 2 3 4 5 6 7 | CriteriaQuery<Project> q = criteriaBuilder.createQuery(Project.class); Root<Status> qFrom = q.from(Status.class); Subquery<Integer> sq = q.subquery(Integer.class); Root<Status> sqFrom = sq.from(Status.class); sq.select(sqFrom.get(Status_.id)) .where(criteriaBuilder.equal(sqFrom.get(Status_.project), qFrom.get(Status_.project)) |
我被困在这里是因为
在上述情况下,对子查询进行排序以获取所需结果的替代方法是什么?
可以使用
1 2 3 4 5 | SELECT q.id_project FROM status q WHERE q.status_name like 'new' AND q.id = ( SELECT MAX(sq.id) from status sq WHERE q.id_project = sq.id_project) |
与查找最大值相比,订购所有记录的速度较慢,这样做的速度也会更快。如已经发布的那样,可以将其转换为CriteriaQuery。
不幸的是,条件查询不支持子查询中的排序-请参阅以下相关答案:
https://stackoverflow.com/questions/19549616#28233425
https://stackoverflow.com/questions/5551459#5551571
如果您确实需要
1 2 | Query query = entityManager.createNativeQuery( "SELECT bar FROM foo WHERE bar IN (SELECT TOP 10 baz FROM quux ORDER BY quuux)"); |
正如您所说,您的子查询将等于的JPQL
1 | SELECT MAX(sq.id) FROM status sq WHERE q.id_project = sq.id_project |
JPA规范应该完全支持它。
就标准API而言,我猜是这样
1 2 3 4 | Subquery<Integer> sq = q.subquery(Integer.class); Root<Status> sqFrom = sq.from(Status.class); Expression maxExpr = criteriaBuilder.max(sqFrom.get(Status_.id)); sq.select(maxExpr).where(criteriaBuilder.equal(sqFrom.get(Status_.project), qFrom.get(Status_.project)) |
除了其他答案外,我认为数据库优化程序无法将具有聚合函数的相关子查询隐式重写为不相关的形式,因此我认为显式编写不相关的子查询在性能方面会更好(以下示例使用JPQL,等同于Criteria API的方法应该很简单):
1 2 3 | select q.project from Status q where q.name = 'new' and q.id in (select max(sq.id) from Status sq group by sq.project.id) |