2014-12-03 53 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")) 
));