如何计算子查询返回的行数?
Posted
技术标签:
【中文标题】如何计算子查询返回的行数?【英文标题】:How do I count the number of rows returned by subquery? 【发布时间】:2011-07-22 09:21:27 【问题描述】:我想做这样的事情:
select count(*) from (select ...)
(就像在 SQL 中一样),但在 JPA 中。
关于我将如何做到这一点的任何想法?
【问题讨论】:
【参考方案1】:这应该可以解决问题(如果您想使用 JPA 标准 API):
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<Entity> root = query.from(Entity.class);
//Selecting the count
query.select(cb.count(root));
//Create your search criteria
Criteria criteria = ...
//Adding search criteria
query.where(criteria);
Long count = getEntityManager().createQuery(query).getSingleResult();
另一方面,如果你想使用 JP-QL,下面的代码应该可以解决问题:
//Add the where condition to the end of the query
Query query = getEntityManager().createQuery("select count(*) from Entity entity where...")
Long count = query.getSingleResult();
【讨论】:
问题是我想获取子查询的返回行数。似乎不可能,因为在JPA中不能像那样使用子查询 这根本没有回答具体问题。 OP 询问的是如何计算子查询的结果,而不是如何计算查询的结果。 如果返回零行则不起作用。 Hibernate 使用javax.persistence.NoResultException
【参考方案2】:
我也偶然发现了这个问题。我最终想执行以下 JPQL:
SELECT COUNT(u)
FROM (
SELECT DISTINCT u
FROM User u
JOIN u.roles r
WHERE r.id IN (1)
)
但这是不可能的,也不能使用标准 API。研究表明,这只是 JPA 中的一个设计限制。 JPA 规范规定子查询仅在 WHERE
和 HAVING
子句中受支持(因此在 FROM
中不支持)。
用以下 JPQL 形式重写查询:
SELECT COUNT(u)
FROM User u
WHERE u IN (
SELECT DISTINCT u
FROM User u
JOIN u.roles r
WHERE r.id IN (1)
)
使用 JPA Criteria API,如下所示:
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<User> u = query.from(User.class);
Subquery<User> subquery = query.subquery(User.class);
Root<User> u_ = subquery.from(User.class);
subquery.select(u_).distinct(true).where(u_.join("roles").get("id").in(Arrays.asList(1L)));
query.select(cb.count(u)).where(cb.in(u).value(subquery));
Long count = entityManager.createQuery(query).getSingleResult();
// ...
已经解决了我的功能需求。这也应该让您有足够的洞察力来解决您的特定功能需求。
【讨论】:
如果要统计聚合查询的结果,不能使用这种方法 @Martin 您建议从任意 CriteriaQuery 中使用什么方法来区分 DISTINCT COUNT? @svlada,我没有找到有效的解决方案,只能返回所有行并在应用服务器上统计它们。 @Martin 在这种情况下,我相信唯一的选择是进行纯 JDBC 查询。【参考方案3】:使用以下 sn-p 计算给定条件查询的行数:
public static Query createNativeCountQuery(EntityManager em, CriteriaQuery<?> criteriaQuery)
org.hibernate.query.Query<?> hibernateQuery = em.createQuery(criteriaQuery).unwrap(org.hibernate.query.Query.class);
String hqlQuery = hibernateQuery.getQueryString();
QueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator(
hqlQuery,
hqlQuery,
Collections.emptyMap(),
em.getEntityManagerFactory().unwrap(SessionFactoryImplementor.class),
null
);
queryTranslator.compile(Collections.emptyMap(), false);
String sqlCountQueryTemplate = "select count(*) from (%s)";
String sqlCountQuery = String.format(sqlCountQueryTemplate, queryTranslator.getSQLString());
Query nativeCountQuery = em.createNativeQuery(sqlCountQuery);
Map<Integer, Object> positionalParamBindings = getPositionalParamBindingsFromNamedParams(hibernateQuery);
positionalParamBindings.forEach(nativeCountQuery::setParameter);
return nativeCountQuery;
private static Map<Integer, Object> getPositionalParamBindingsFromNamedParams(org.hibernate.query.Query<?> hibernateQuery)
Map<Integer, Object> bindings = new HashMap<>();
for (var namedParam : hibernateQuery.getParameterMetadata().getNamedParameters())
for (int location : namedParam.getSourceLocations())
bindings.put(location + 1, hibernateQuery.getParameterValue(namedParam.getName()));
return bindings;
【讨论】:
除了枚举和列表参数外,它可以工作以上是关于如何计算子查询返回的行数?的主要内容,如果未能解决你的问题,请参考以下文章