2017-08-15 90 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)));