English 中文(简体)
JPQL / QueryDSL: join subquery and get aliased column
原标题:

I m trying to get an average for a count on a groupBy by joining with a subquery. Don t know if that the right way to go at all but I couldn t anything about subqueries other than the mysema doc.

Scenario: How many orders per product did a customer do on average? Meaning: A Customer orders products. So a customer ordered a specific product a number of times (count). What s the average number of orders that customer placed for any product?

Might sound a bit hypothetical, in fact it s just part of a prototype, but it made me wonder, how to get a reference to a custom column created within a subquery with the fancy QueryDSL from Mysema.

In SQL you just give the count column an alias and join using a second ID column. QueryDSL has the "as()" method as well but I have no Idea, how to retrieve that column plus I dont t see how it can join one query with anothers, since query.list() just gets a list but for some reason the join accepts it. Feels wrong...

Here s my code:

    JPQLQuery query = createJPQLQuery();

    QOrdering qOrdering = QOrdering.ordering;
    QProduct qProduct = QProduct.product;
    QCustomer qCustomer = QCustomer.customer;           

    // how many of each product did a customer order?
    HibernateSubQuery subQuery = new HibernateSubQuery();
    subQuery.from(qOrdering).innerJoin(qOrdering.product,qProduct).innerJoin(qOrdering.customer, qCustomer);
    subQuery.groupBy(qCustomer,qProduct).list(qCustomer.id,qProduct.id,qProduct.count());

    // get the average number of orders per product for each customer
    query.from(qCustomer);      
    query.innerJoin(subQuery.list(qCustomer.id,qOrdering.count().as("count_orders")));      
    query.groupBy(qCustomer.id);
    return (List<Object[]>) query.list(qCustomer.firstname,subQuery.count_orders.avg());

Again: How do I join with a subquery? How do I get the aliased "count" column to do more aggregation like avg (is my group right btw?) Might be that I have some other errors in this, so any help appreciated!

Thanks!

Edit: That s kind of the native SQL I d like to see QueryDSL produce:

Select avg(numOrders) as average, cust.lastname from
customer cust
inner join
(select count(o.product_id) as numOrders, c.id as cid, p.name
from ordering o
inner join product p on o.product_id=p.id
inner join customer c on o.customer_id=c.id
group by o.customer_id, o.product_id) as numprods
on cust.id = numprods.cid
group by numprods.cid
order by cust.lastname;
最佳回答

Using subqueries in the join clause is not allowed. in JPQL, subqueries are only allowed in the WHERE and HAVING part. The join method signatures in Querydsl JPA queries are too wide.

As this query needs two levels of grouping, maybe it can t be expressed with JPQL / Querydsl JPA.

I d suggest to write this query using the Querydsl JPA Native query support.

As Querydsl JPA uses JPQL internally, it is restricted by the expressiveness of JPQL.

问题回答

I know that this question is old and already has an accepted answer, but judging from this question, it seems to still be troubling guys. See my answer in the same question. The use of JoinFlag in the join() section and Expression.path() is able to achieve left-joining a subquery. Hope this helps someone.

QueryDsl does not support subQuery in join but you can achieve this via following way:

We wanted to achieve the following query:

select A.* from A join (select aid from B group by aid) b on b.aid=A.id;

Map a View or SQL query to JPA entity:

import lombok.Setter;
import org.hibernate.annotations.Subselect;
import org.hibernate.annotations.Synchronize;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Getter
@Setter
@Subselect("select aid from B group by aid")
@Synchronize("B")
public class BGroupByAid {

    @Id
    private Integer aId;
}

then use the equivalent QueryDSl entity in the class just like the regular entity:

JPAQuery<QAsset> query = new JPAQuery<>(entityManager);  
QBGroupByAid bGroupById = QBGroupByAid.bGroupByAid;

 List<A> tupleOfAssets =
            query.select(A)
        .from(A).innerJoin(bGroupById).on(bGroupById.aId.eq(A.aId))
        .fetchResults()
        .getResults();
        

You can also use blazebit which supports also subquery in join. I have try it and it is working. You can create SubQueryExpression f.e like this

SubQueryExpression<Tuple> sp2 = getQueryFactory().select(entity.id,
                        JPQLNextExpressions.rowNumber().over().partitionBy(entity.folId).orderBy(entity.creationDate.desc()).as(rowNumber))
                .from(entity)
                .where(Expressions.path(Integer.class, rowNumber).eq(1));

and then just join it like this:

return getBlazeQueryFactory()
                .select(entity1, entity)
                .from(entity1)
                .leftJoin(sp2, entity).on(entity.id.eq(entity1.id)).fetch();

I have put here just simple example. So maybe it doesn t make a perfect sense but maybe can be helpful.

Also don t be confused it will can produce union in the generated select. This is just for naming columns from subquery you can read better explanation about this union here: Blaze-Persistence GROUP BY in LEFT JOIN SUBQUERY with COALESCE in root query





相关问题
Cannot perform an aggregate function on a subquery

Can someone help me with this query? SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentinalRent, SUM( (SELECT COUNT(t.ID) * ru.MonthlyRent FROM tblTenant t WHERE t.UnitID = ru.ID) ) AS ...

NHibernate Joining on non-mapped property

I have two classes SystemInvitation and User. User has a property called Email and SystemInvitation has a property called InviteesEmailAddress. There is no relationship in the domain between these ...

Subquery to String?

I have a table containing countries: id country ------------ 0 Monaco 1 Mongolia 2 Montenegro 3 Morocco 4 Mozambique 5 Myanmar I have a sub query that looks like this. (...

MySQL: Returning multiple columns from an in-line subquery

I m creating an SQL statement that will return a month by month summary on sales. The summary will list some simple columns for the date, total number of sales and the total value of sales. However, ...

Performance of Sql subqueriesfunctions

I am currently working on a particularly complex use-case. Simplifying below :) First, a client record has a many-to-one relationship with a collection of services, that is, a single client may have ...

热门标签