2014-12-03 52 views
4

我试图将此SQL查询转换为使用JPA条件生成器。 答案需要是双重或浮动。如何将SQL查询转换为子查询并计入JPA条件生成器

SELECT CAST((COUNT(m.id) - 
(SELECT COUNT(s.id) 
    FROM mobile_unit as s 
    left JOIN incident as i ON s.incidentId=i.id 
    JOIN organizational_unit as o ON s.organizationalUnitId=o.id 
    WHERE (s.organizationalUnitId = 1 AND s.incidentId IS NULL))) AS float) 
/COUNT(m.id) 
FROM mobile_unit as m 
JOIN organizational_unit as o ON m.organizationalUnitId=o.id 
WHERE m.organizationalUnitId = 1 
+0

我不确定为什么要使用子查询,当它不以任何方式与外部查询相关时。在三个表之间进行查询不是更有意义吗?只需在Java中进行计算?另外,加入到'incidentId'上的'incident',你可以过滤出非空值,这对我来说完全是多余的。最后,你并没有将两个连接中的任何一个连接到'organizational_unit',所以为什么要打扰他们呢? – 2014-12-03 08:23:29

+0

@DavidWallace感谢您的评论。子查询返回需要在外部查询中使用的计数答案。我需要子查询来返回只有incidentId不为null的mobile_unit的计数,也许有更好的办法做到这一点。加入原始单元仅适用于稍后在项目中进行测试。在这一天结束时,我写了2个查询,并在java代码中进行了计算,但我仍然想知道是否可以在JPA中执行此操作。 – VickiG 2014-12-04 09:45:32

+0

恩,我想是的。我对使用JPA Criteria Builders进行聚合函数有点模糊,这就是为什么我不愿写出答案的原因。但是在SQL中,您所做的只是计算其中incidentId不为null的mobile_unit行的比例,超过organizationalUnitId为1的那些行。所有连接都是不相关的,可以完全删除。因此,我可以用SQL编写这个最简单的方法是SELECT CAST(COUNT(incidentId)AS FLOAT)/ COUNT(*)FROM mobile_unit WHERE organizationalUnitId = 1' - 这与您的SQL完全等价。我的部分... – 2014-12-04 10:21:19

回答

0

没有测试此,这里是如何可以做一个粗略的草图。

CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Float> cq = cb.createQuery(Float.class); 

Root<MobileUnit> root = cq.from(MobileUnit.class); 
// Join is actually unnecessary 
root.join("organizationalUnit", JoinType.INNER); 
cq.where(cb.equal(
    root.get("organizationalUnitId"), 
    1 
)); 

Subquery<Long> subquery = cq.subquery(Long.class); 
Root<MobileUnit> subRoot = subquery.from(MobileUnit.class); 
// Actually these joins are unnecessary, but you requested them.. 
subRoot.join("incident", JoinType.LEFT); 
subRoot.join("organizationalUnit", JoinType.INNER); 

subquery.select(cb.count(subRoot.get("id"))); 
subquery.where(cb.and(
    subRoot.get("organizationalUnitId").eq(cb.literal(1)), 
    subRoot.get("incidentId").isNull() 
)); 

cq.select(cb.quot(
    cb.diff(
     cb.count(root.get("id")), 
     subquery 
    ).as(Float.class), 
    cb.count(root.get("id")) 
));