考虑以下两个表:
Project ( id, project_name)
Status ( id, id_project, status_name)
Status
包含Project
所有的所有状态。
让我们说我们想要查询最新状态名称为" new"的所有项目。我想出的Sql查询是:
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的方法为orderBy
,但类Subquery没有。
我到目前为止提出的标准查询是:
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))
我被困在这里,因为Subquery sq
没有任何方法可以对结果进行排序,只返回最新结果。
为了在上述场景中获得所需结果,对子查询进行排序有哪些替代方法?
答案 0 :(得分:2)
正如您所说,您的子查询等同于
的JPQLSELECT MAX(sq.id) FROM status sq WHERE q.id_project = sq.id_project
应该完全支持JPA规范。 就Criteria API而言,我猜这个
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))
答案 1 :(得分:2)
子查询可以使用SELECT MAX
而不是SELECT TOP 1 ... ORDER BY ...
来编写:
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。
不幸的是,Criteria Queries不支持子查询中的排序 - 请参阅以下相关答案:
https://stackoverflow.com/questions/19549616#28233425 https://stackoverflow.com/questions/5551459#5551571
如果确实需要ORDER BY
(例如,在下面的示例中允许一系列值),则另一种方法是使用本机查询而不是CriteriaQuery:
Query query = entityManager.createNativeQuery(
"SELECT bar FROM foo WHERE bar IN (SELECT TOP 10 baz FROM quux ORDER BY quuux)");
答案 2 :(得分:1)
除了其他答案,我不认为数据库优化器能够隐式地将具有聚合函数的相关子查询重写为不相关的形式,因此我认为明确地编写不相关的子查询在性能方面更好(下面的例子)使用JPQL,Criteria API等价物应该是直截了当的):
SharedModule