使用JPA Criteria API将子查询SELECT作为字段

时间:2018-10-24 13:42:36

标签: java sql jpa jpa-criteria

我有以下SQL查询:

select
        A.A_ID,
        B.Lib,
        A.Lib,
        C.Lib,
        (SELECT count(*) FROM X WHERE A.A_ID = X.A_ID) AS countX,
        (SELECT count(*) FROM Y WHERE A.A_ID = Y.A_ID) AS countY,
        (SELECT count(*) FROM Z WHERE A.A_ID = Z.A_ID) AS countZ
    from
        A
    left outer join
        C
            on A.C_ID=C.C_ID
    left outer join
        B
            on A.B_ID=B.B_ID;

我想使用JPA Criteria API创建此查询,所以我做了如下操作:

final CriteriaBuilder builder = getCriteriaBuilder();
final CriteriaQuery<A_DTO> criteriaQuery = builder.createQuery(A_DTO.class);
final Root<A> aRoot = criteriaQuery.from(A.class);

// LEFT OUTER JOIN B
Join<A, B> bJoin = aRoot.join(A_.bID, JoinType.LEFT);
// LEFT OUTER JOIN C
Join<A, C> cJoin = aRoot.join(A_.cID, JoinType.LEFT);

// (SELECT count(*) FROM X WHERE A.A_ID = X.A_ID) AS countX
final Subquery<X> xSubquery = criteriaQuery.subquery(X.class);
final Root<X> xRoot = xSubquery.from(X.class);
xRoot.alias("countX");
xSubquery.select(xRoot);
xSubquery.where(builder.equal(xRoot.get(X_.a).get(A_.aID), aRoot.get(A_.aID)));

// (SELECT count(*) FROM Y WHERE A.A_ID = Y.A_ID) AS countY
final Subquery<Y> ySubquery = criteriaQuery.subquery(Y.class);
final Root<Y> yRoot = ySubquery.from(Y.class);
yRoot.alias("countY");
ySubquery.select(yRoot);
ySubquery.where(builder.equal(yRoot.get(Y_.a).get(A_.aID), aRoot.get(A_.aID)));

// (SELECT count(*) FROM Z WHERE A.A_ID = Z.A_ID) AS countZ
final Subquery<Z> zSubquery = criteriaQuery.subquery(Z.class);
final Root<Z> zRoot = zSubquery.from(Z.class);
zRoot.alias("countZ");
zSubquery.select(zRoot);
zSubquery.where(builder.equal(zRoot.get(Z_.a).get(A_.aID), aRoot.get(A_.aID)));

// Selection
criteriaQuery.multiselect(aRoot.get(A_.aID),
        bJoin.get(B_.lib),
        aRoot.get(A_.lib),
        cJoin.get(C_.lib),
        builder.count(xRoot),
        builder.count(yRoot),
        builder.count(zRoot));

return getEntityManager().createQuery(criteriaQuery);

但这对我不起作用,而是生成以下SQL查询:

select
    a0_.aID as col_0_0_,
    b2_.Lib as col_1_0_,
    a0_.Lib as col_3_0_,
    c1_.Lib as col_4_0_,
    count(countX) as col_5_0_,
    count(countY) as col_6_0_,
    count(countZ) as col_7_0_
from
    A a0_
left outer join
    C c1_
        on a0_.cID=c1_.cID
left outer join
    B b2_
        on a0_.bID=b2_.bID;

这将引发以下SQL异常:

  

WARN o.h.e.j.s.SqlExceptionHelper-SQL错误:904,SQLState:42000

     

错误o.h.e.j.s.SqlExceptionHelper-ORA-00904:“ countZ”:无效   标识符

我该如何解决这个问题?

编辑:

我已经使用以下代码解决了这个问题:

final CriteriaBuilder builder = getCriteriaBuilder();
final CriteriaQuery<A_DTO> criteriaQuery = builder.createQuery(A_DTO.class);
final Root<A> aRoot = criteriaQuery.from(A.class);

// LEFT OUTER JOIN B
Join<A, B> bJoin = aRoot.join(A_.bID, JoinType.LEFT);
// LEFT OUTER JOIN C
Join<A, C> cJoin = aRoot.join(A_.cID, JoinType.LEFT);

// (SELECT count(*) FROM X WHERE A.A_ID = X.A_ID) AS countX
final Subquery<Long> xSubquery = criteriaQuery.subquery(Long.class);
final Root<X> xRoot = xSubquery.from(X.class);
final Expression<Long> xCount = builder.count(xRoot);
xSubquery.select(xCount);
xSubquery.where(builder.equal(xRoot.get(X_.a).get(A_.aID), aRoot.get(A_.aID)));

// (SELECT count(*) FROM Y WHERE A.A_ID = Y.A_ID) AS countY
final Subquery<Long> ySubquery = criteriaQuery.subquery(Long.class);
final Root<Y> yRoot = ySubquery.from(Y.class);
final Expression<Long> yCount = builder.count(yRoot);
ySubquery.select(yCount);
ySubquery.where(builder.equal(yRoot.get(Y_.a).get(A_.aID), aRoot.get(A_.aID)));

// (SELECT count(*) FROM Z WHERE A.A_ID = Z.A_ID) AS countZ
final Subquery<Long> zSubquery = criteriaQuery.subquery(Long.class);
final Root<Z> zRoot = zSubquery.from(Z.class);
final Expression<Long> zCount = builder.count(zRoot);
zSubquery.select(zCount);
zSubquery.where(builder.equal(zRoot.get(Z_.a).get(A_.aID), aRoot.get(A_.aID)));

// Selection
criteriaQuery.multiselect(aRoot.get(A_.aID),
        bJoin.get(B_.lib),
        aRoot.get(A_.lib),
        cJoin.get(C_.lib),
        xSubquery.getSelection(),
        ySubquery.getSelection(),
        zSubquery.getSelection());

return getEntityManager().createQuery(criteriaQuery);

但是当我想根据计数值选择结果或使用它对结果进行排序时,我必须按以下方式更改查询:

WITH cte AS ( select
        A.A_ID,
        B.Lib,
        A.Lib,
        C.Lib,
        (SELECT count(*) FROM X WHERE A.A_ID = X.A_ID) AS countX,
        (SELECT count(*) FROM Y WHERE A.A_ID = Y.A_ID) AS countY,
        (SELECT count(*) FROM Z WHERE A.A_ID = Z.A_ID) AS countZ
    from
        A
    left outer join
        C
            on A.C_ID=C.C_ID
    left outer join
        B
            on A.B_ID=B.B_ID)
    SELECT * FROM cte 
    WHERE countX > 2 
    ORDER BY countY, countZ DESC;

现在我不知道如何在JPA Criteria API中创建此通用表表达式。

0 个答案:

没有答案