【问题标题】:JPQL / QueryDSL: join subquery and get aliased columnJPQL / QueryDSL:加入子查询并获取别名列
【发布时间】:2011-10-20 00:05:59
【问题描述】:

我试图通过加入子查询来获得 groupBy 计数的平均值。不知道这是否是正确的方法,但除了 mysema 文档之外,我对子查询一无所知。

场景: 客户平均每个产品做了多少订单? 含义:客户订购产品。因此,客户多次(计数)订购了特定产品。客户为任何产品下的平均订单数是多少?

听起来有点假设,实际上它只是原型的一部分,但它让我想知道,如何使用来自 Mysema 的精美 QueryDSL 获取对在子查询中创建的自定义列的引用。

在 SQL 中,您只需给计数列一个别名,然后使用第二个 ID 列进行连接。 QueryDSL 也有“as()”方法,但我不知道如何检索该列,而且我不知道它如何将一个查询与另一个查询连接起来,因为 query.list() 只是获取一个列表,但对于某些加入接受它的原因。感觉不对……

这是我的代码:

    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());

再次:如何加入子查询? 如何让别名“count”列进行更多聚合,如 avg(顺便说一句,我的组对吗?) 可能是我在这方面有一些其他错误,所以任何帮助表示赞赏!

谢谢!

编辑: 这就是我希望 QueryDSL 产生的原生 SQL:

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;

【问题讨论】:

    标签: subquery jpql querydsl


    【解决方案1】:

    不允许在连接子句中使用子查询。在 JPQL 中,子查询只允许在 WHERE 和 HAVING 部分。 Querydsl JPA 查询中的连接方法签名太宽。

    由于该查询需要两级分组,可能无法用JPQL/Querydsl JPA表示。

    我建议使用 Querydsl JPA Native 查询支持来编写这个查询。

    由于 Querydsl JPA 内部使用 JPQL,因此受到 JPQL 表达能力的限制。

    【讨论】:

    • 谢谢!太糟糕了,因为我正在考虑基于 QueryDSL 和任何理论限制手段构建通用搜索,我必须考虑如何将替代技术包含到我的搜索标记中......
    • 虽然转念一想:如何访问别名 count() 列?
    • 对于别名计数列,请改用Path实例(路径别名,subQuery.as(alias),之后再使用别名)
    • 现在似乎可以做到这一点stackoverflow.com/a/15022136/2037762
    【解决方案2】:

    我知道这个问题很老,并且已经有一个公认的答案,但是从this question 来看,它似乎仍然令人不安。在同一个问题中查看我的答案。在join() 部分中使用JoinFlagExpression.path() 可以实现子查询的左连接。希望这对某人有所帮助。

    【讨论】:

      【解决方案3】:

      QueryDsl 不支持连接中的 subQuery,但您可以通过以下方式实现:

      我们想要实现以下查询:

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

      将视图或 SQL 查询映射到 JPA 实体:

      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;
      }
      

      然后像普通实体一样在类中使用等效的 QueryDSl 实体:

      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();
              
      

      【讨论】:

        猜你喜欢
        • 2013-05-03
        • 2011-09-17
        • 1970-01-01
        • 2014-07-13
        • 2012-04-11
        • 2016-09-24
        • 2011-06-27
        • 1970-01-01
        • 2023-01-30
        相关资源
        最近更新 更多