2017-08-15 149 views
0

多列,我想設計一個查詢像這樣:JPA標準查詢與子查詢

SELECT * 
FROM TableA 
WHERE (a AND b AND C) NOT IN 
    (SELECT * 
    FROM TableB 
    WHERE TableB.id != 1234) 

我真正想要做的是得到表A中的所有記錄,除非出現了一列的值, b和c都在表B中,並且ID恰好是1234.

catch(或者我認爲)是我需要以某種方式構造此查詢,以便根據上述查詢進行過濾,但那麼它還需要匹配其他謂詞列表,使其看起來像這樣:

CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<TableA> q = cb.createQuery(TableA.class); 
Root<TableA> c = q.from(TableA.class); 


Subquery<TableB> sq = q.subquery(TableB.class); 
Root<TableB> ac = sq.from(TableB.class); 

List<Predicate> predicates = new ArrayList<Predicate>(); 

sq.select(ac); 
sq.where(cb.equal(ac.get("id"), 1234)); 

predicates.add(cb.not(cb.in(c.get("a")).value(sq))); 
predicates.add(cb.not(cb.in(c.get("b")).value(sq))); 
predicates.add(cb.not(cb.in(c.get("c")).value(sq))); 


.... 
more predicates added 
.... 

q.where(predicates.toArray(new Predicate[]{})); 

以上是我的方法之一,但沒有得到正確的結果。

回答

0

爲了解決您的問題,您可以使用IN子句將查詢轉換爲帶有EXISTS子句的查詢。 實施例:

SELECT * 
    FROM TableA ta 
WHERE (ta.a, ta.b) NOT IN 
(SELECT tb.a, tb.c 
    FROM TableB tb 
    WHERE tb.id != 1234) 

SELECT * 
    FROM TableA ta 
WHERE NOT EXISTS 
    (SELECT 1 
     FROM TableB tb 
     WHERE ta.a = tb.a AND ta.b = tb.b 
     AND TableB.id != 1234) 

你的代碼,使用JPA CriteriaBuilder將被修改爲:

CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<TableA> criteria = cb.createQuery(TableA.class); 
Root<TableA> rootTableA = criteria.from(TableA.class); 

Subquery<TableB> sq = criteria.subquery(TableB.class); 
Root<TableB> rootTableB = sq.from(TableB.class); 
sq.select(rootTableB); 

List<Predicate> subQueryPredicates = new ArrayList<Predicate>(); 
subQueryPredicates.add(cb.equal(rootTableA.get("a"), rootTableB.get("a"))); 
subQueryPredicates.add(cb.equal(rootTableA.get("b"), rootTableB.get("b"))); 
subQueryPredicates.add(cb.equal(rootTableB.get("id"), 1234)); 
sq.where(subQueryPredicates.toArray(new Predicate[]{})); 

criteria.where(cb.not(cb.exists(sq)));