QueryDSL技术咨询:WHERE子句能否用count(*)及聚合SQL转换
嘿,针对你的两个问题,我来详细解答下:
问题1:QueryDSL中WHERE子句能否使用count(*)?
直接在WHERE子句里用count(*)是不行的哦。因为count(*)是聚合函数,它是基于分组后的结果计算的,而WHERE子句的作用是在分组之前筛选原始行数据。如果要过滤聚合后的结果,通常有两种方式:
- 如果是在分组后直接过滤,用
HAVING子句(比如分组后直接筛选count>2的简单场景); - 如果是像你提供的SQL那样,需要先把聚合结果作为子查询,再在外层用WHERE筛选,这种方式QueryDSL是完全支持的。
问题2:将指定SQL转换为QueryDSL实现
先把你给出的SQL列出来方便对照:
select tcc.catcode, tcc.catcount from (select g.code catcode, count(*) catcount from dwh_aggregated_order a join cat_product_category g on g.id=a.product_category_id group by g.code) tcc where tcc.catcount > 2
下面是对应的QueryDSL实现(假设你用的是JPAQueryFactory,且已经生成了对应的Q实体类):
首先定义Q类实例:
QDwhAggregatedOrder a = QDwhAggregatedOrder.dwhAggregatedOrder; QCatProductCategory g = QCatProductCategory.catProductCategory;
然后构建子查询,对应SQL里的内层聚合查询:
// 构建内层聚合查询,统计各分类的售出数量 SubQueryExpression<Tuple> subQuery = JPAExpressions .select(g.code.as("catcode"), a.count().as("catcount")) .from(a) .join(g).on(g.id.eq(a.productCategoryId)) .groupBy(g.code);
接下来外层查询,筛选出数量大于2的分类:
// 给子查询结果定义别名,方便后续引用 QTuple tcc = new QTuple(subQuery.get(0).as("catcode"), subQuery.get(1).as("catcount")); // 执行外层查询,获取最终结果 List<Tuple> result = queryFactory .select(tcc.catcode, tcc.catcount) .from(subQuery.as(tcc)) .where(tcc.catcount.gt(2L)) // count返回的是Long类型,注意匹配数据类型 .fetch();
如果你需要把结果映射到自定义的DTO类(比如CategorySalesCount,包含catcode和catcount属性),也可以直接用投影转换:
// 假设存在CategorySalesCount类,有对应的getter/setter List<CategorySalesCount> dtoResult = queryFactory .select(Projections.bean(CategorySalesCount.class, tcc.catcode.as("catcode"), tcc.catcount.as("catcount"))) .from(subQuery.as(tcc)) .where(tcc.catcount.gt(2L)) .fetch();
这样就完全实现了你给出的SQL逻辑:先统计各分类的售出产品数量,再筛选出数量超过2的分类。
内容的提问来源于stack exchange,提问作者czetsuya
相关产品推荐
相关产品推荐

